Javascript while loop
Содержание:
Flowchart of while Loop
Flowchart of JavaScript while loop
Example 1: Display Numbers from 1 to 5
Output
1 2 3 4 5
Here is how this program works.
Iteration | Variable | Condition: i <= n | Action |
---|---|---|---|
1st | 1 is printed. i is increased to 2. | ||
2nd | 2 is printed. i is increased to 3. | ||
3rd | 3 is printed. i is increased to 4. | ||
4th | 4 is printed. i is increased to 5. | ||
5th | 5 is printed. i is increased to 6. | ||
6th | The loop is terminated |
Example 2: Sum of Positive Numbers Only
Output
Enter a number: 2 Enter a number: 5 Enter a number: 7 Enter a number: 0 Enter a number: -3 The sum is 14.
In the above program, the user is prompted to enter a number.
Here, is used because takes input from the user as a string. And when numeric strings are added, it behaves as a string. For example, . So converts a numeric string to number.
The loop continues until the user enters a negative number. During each iteration, the number entered by the user is added to the variable.
When the user enters a negative number, the loop terminates. Finally, the total sum is displayed.
Рекурсивный setTimeout
Есть два способа запускать что-то регулярно.
Один из них . Другим является рекурсивный . Например:
Метод выше планирует следующий вызов прямо после окончания текущего .
Рекурсивный – более гибкий метод, чем . С его помощью последующий вызов может быть задан по-разному в зависимости от результатов предыдущего.
Например, необходимо написать сервис, который отправляет запрос для получения данных на сервер каждые 5 секунд, но если сервер перегружен, то необходимо увеличить интервал запросов до 10, 20, 40 секунд…
Вот псевдокод:
А если функции, которые мы планируем, ресурсоёмкие и требуют времени, то мы можем измерить время, затраченное на выполнение, и спланировать следующий вызов раньше или позже.
Рекурсивный позволяет задать задержку между выполнениями более точно, чем .
Сравним два фрагмента кода. Первый использует :
Второй использует рекурсивный :
Для внутренний планировщик будет выполнять каждые 100 мс:
Обратили внимание?
Реальная задержка между вызовами с помощью меньше, чем указано в коде!
Это нормально, потому что время, затраченное на выполнение , использует часть заданного интервала времени.
Вполне возможно, что выполнение будет дольше, чем мы ожидали, и займёт более 100 мс.
В данном случае движок ждёт окончания выполнения и затем проверяет планировщик и, если время истекло, немедленно запускает его снова.
В крайнем случае, если функция всегда выполняется дольше, чем задержка , то вызовы будут выполняться без задержек вообще.
Ниже представлено изображение, показывающее процесс работы рекурсивного :
Рекурсивный гарантирует фиксированную задержку (здесь 100 мс).
Это потому, что новый вызов планируется в конце предыдущего.
Сборка мусора и колбэк setTimeout/setInterval
Когда функция передаётся в , на неё создаётся внутренняя ссылка и сохраняется в планировщике. Это предотвращает попадание функции в сборщик мусора, даже если на неё нет других ссылок.
Для функция остаётся в памяти до тех пор, пока не будет вызван .
Есть и побочный эффект. Функция ссылается на внешнее лексическое окружение, поэтому пока она существует, внешние переменные существуют тоже. Они могут занимать больше памяти, чем сама функция. Поэтому, если регулярный вызов функции больше не нужен, то лучше отменить его, даже если функция очень маленькая.
Присваивание
Давайте отметим, что в таблице приоритетов также есть оператор присваивания . У него один из самых низких приоритетов: .
Именно поэтому, когда переменной что-либо присваивают, например, , то сначала выполнится арифметика, а уже затем произойдёт присваивание с сохранением результата в .
Тот факт, что является оператором, а не «магической» конструкцией языка, имеет интересные последствия.
Большинство операторов в JavaScript возвращают значение. Для некоторых это очевидно, например сложение или умножение . Но и оператор присваивания не является исключением.
Вызов записывает в и возвращает его.
Благодаря этому присваивание можно использовать как часть более сложного выражения:
В примере выше результатом будет значение, которое присваивается переменной (то есть ). Потом оно используется для дальнейших вычислений.
Забавное применение присваивания, не так ли? Нам нужно понимать, как это работает, потому что иногда это можно увидеть в JavaScript-библиотеках.
Однако писать самим в таком стиле не рекомендуется. Такие трюки не сделают ваш код более понятным или читабельным.
Рассмотрим ещё одну интересную возможность: цепочку присваиваний.
Такое присваивание работает справа налево. Сначала вычисляется самое правое выражение , и затем результат присваивается переменным слева: , и . В конце у всех переменных будет одно значение.
Опять-таки, чтобы код читался легче, лучше разделять подобные конструкции на несколько строчек:
Польза от такого стиля особенно ощущается при быстром просмотре кода.
Оператор цикла for
В JavaScript циклы чаще всего создаются с помощью
оператора цикла for. Он выглядит так:
+
9101112 |
for (var i=1; i<5; i++) { document.write(i); } |
У оператора for содержится в скобках три выражения, разделённых
точкой с запятой. Эти выражения имеют такой смысл:
Первое выражение. В нём задаётся начальное значение определённой переменной.
Обычно её называют i. Хотя её можно назвать как угодно, это просто переменная. Первое выражение выполняется
один раз в начале цикла и больше не используется. Если переменная i не была объявлена ранее, то её
можно объявить прямо в цикле.
Второе выражение. Содержит условие, при котором цикл выполняется. Когда
условие перестаёт выполняться, цикл прекращается.
Третье выражение. В нём производится изменение значения переменной i.
Далее в фигурных скобках следуют строки, которые выполняются в цикле.
Порядок работы оператора for такой:
- В первом выражении переменная i получает начальное значение.
- Затем проверяется условие во втором выражении. Если условие верно, то выполняются
строки в фигурных скобках. - После этого в третьем выражении переменная i меняет значение и вновь проверяется
условие. Если оно опять верно, то ещё раз выполняются строки в фигурных скобках. И снова
меняется значение i, и снова проверяется условие.Так происхожит до тех пор, пока условие не перестанет
выполняться. - Если условие неверно, то строки цикла не выполняются, цикл прекращается и начинают работать
строки, следующие за закрывающей фигурной скобкой.
В предложенном примере переменная i имеет начальное значение 1. После выполнения строк цикла она каждый
раз увеличивается на единицу. Цикл выполняется до тех пор, пока i меньше 5. В фигурных скобках
содержится только одна строка. Она выводит на экран текущее значение переменной i.
Создайте страницу и добавьте на неё опрератор
for так, как он написан в примере. Запустите страницу и посмотрите как оператор
работает. Затем попробуйте что нибудь изменить в операторе. Измените начальное значение или условие цикла,
добавьте другие строки в цикл.
Строки, которые находятся в фигурных скобках, называются тело цикла. Одно выполнение этих строк называется
итерация. Если строки выполнились 5 раз, то это 5 итераций.
Операторы break и continue
Циклом можно управлять с помощью операторов break и continue.
Оператор break приводит к выходу из цикла или инструкции и передает управление
операторам, следующим за ними.
В следующем примере создаётся счётчик, значения которого должны изменяться от до , однако оператор break прерывает цикл после итераций:
Выполнить код »
Скрыть результаты
Для вложенных циклов оператор используется с меткой, с помощью которой завершается работа «меченой» инструкции. Метка позволяет выйти из любого блока кода. Метка имеет вид , имя должно быть уникальным. Она ставится перед циклом или блоком инструкций, которые нужно завершить с помощью :
Выполнить код »
Скрыть результаты
Указание имени метки (без двоеточия) за ключевым словом приводит к выходу из цикла или инструкции. Между ключевым словом и именем метки не допускается перевод строки. Вызов завершит вложенный цикл, а ищет ближайший внешний цикл с такой меткой и переходит в его конец.
Оператор continue прерывает текущее выполнение цикла и переходит к выполнению следующего шага этого цикла. При этом, цикл возвращается непосредственно к своему условию, а цикл сначала вычисляет выражение инкремента, а затем возвращается к условию.
Рассмотрим пример:
Выполнить код »
Скрыть результаты
В теле цикла инструкция с помощью оператора проверяет, является ли число четным. Если да, итерация цикла завершается до увеличения переменной , но цикл продолжается со следующей итерации со значением , увеличенным на единицу. Затем цикл выполняется до естественного завершения при значении , равном 10. Переменная подсчитывает количество итераций цикла. Окончательное значение равно 5, а не 9, потому что четные операции инкремента пропускаются из-за оператора .
Оператор , как и , можно использовать вместе с «помеченными» инструкциями для
возврата к конкретному месту в коде. Чаще всего это делается во вложенных циклах, например:
Выполнить код »
Скрыть результаты
В этом примере для внешнего цикла добавлена метка outer_mask. Каждый цикл включает 5 итераций, то есть инструкция предположительно должна быть выполнена 25 раз, после чего переменная должна быть равна 25. Оператор завершает выполнение внутреннего цикла, начиная новую итерацию внешнего. Она выполняется, когда равно 3, то есть пропускаются две итерации внутреннего цикла, из-за чего в итоге имеет значение 23.
setTimeout и setInterval
В JavaScript имеются методы, которые позволяют вызвать функцию не сразу, а через некоторый промежуток времени (в асинхронном режиме). Называются они и .
Отличаются они друг от друга лишь тем, что выполняет вызов функции всего один раз, а – постоянно через указанный интервал времени.
Синтаксис и :
// setTimeout window.setTimeout(func ); // setInterval window.setTimeout(func );
Параметры:
- – функция, которую нужно вызвать спустя указанное в количество миллисекунд;
- – количество миллисекунд по истечении которых нужно выполнить ;
- – дополнительные аргументы, которые нужно передать в .
Например, вызовем функцию один раз по прошествии 3 секунд:
// функция function myFunc() { console.log('after 3 seconds'); } // вызовем функцию myFunc после 3 секунд window.setTimeout(myFunc, 3000); // выведем сообщение в консоль console.log('immediately');
При выполнение этого кода программа не остановится на месте, где мы зарегистрировали некоторую асинхронность посредством и не будет блокировать её дальнейшее выполнение на 3 секунды, через которые нужно будет вызвать . Выполнение скрипта продолжится дальше и сначала браузер выведет в консоль сообщение «immediately», а затем через 3 секунды – «after 3 seconds».
Другими словами, когда браузер доходит до исполнения , он как бы помещает функцию в некоторое место, а затем по прошествии определённого количества времени её вызывает. При этом блокировка основного потока выполнения программы не происходит.
Чтобы более подробно разобраться в этом необходимо рассмотреть, как движок JavaScript выполняет синхронный и асинхронный код, а также что такое event loop и как он работает.
Синхронный и асинхронный код
Но перед тем, как переходить к асинхронными операциям, следует сначала в общих чертах разобраться как выполняется синхронный код.
Выполнение такого кода движок JavaScript выполняет последовательно (т.е. строчку за строчкой). При этом перед тем, как выполнить какую-то строчку кода интерпретатор сначала помещает её в стек вызовов (call stack). Именно в нём происходит её разбор и исполнение. После этого происходит её извлечение из стека и переход к следующей строчке.
Но всё меняется, когда интерпретатор доходит до выполнения асинхронных операций, например . Они также как и синхронные операции сначала попадают в стек вызовов, где происходит их разбор. Но, при разборе интерпретатор понимает, что это некоторый вызов Web API и помещает эту операцию в него. После этого он удаляет эту строчку из call stack и переходит к выполнению следующей строчки кода.
В это же время Web API регистрирует эту функцию и запускает таймер. Как только он завершается, он помещает эту функцию в очередь (callback queue). Очередь – это структура данных типа FIFO. Она хранит все функции в том порядке, в котором они были туда добавлены.
Очередь обратных вызовов (callback queue) обрабатывает цикл событий (event loop). Он смотрит на эту очередь и на стек вызовов (call stack). Если стек вызовов пуст, а очередь нет – то он берёт первую функцию из очереди и закидывает её в стек вызовов, в котором она уже выполняется. Вот таким образом происходит выполнения асинхронного кода в JavaScript.
Если функцию необходимо вызывать не один раз, а постоянно через каждые 3 секунды, то тогда вместо следует использовать :
window.setInterval(myFunc, 3000);
Пример, с передачей функции аргументов:
function sayHello(name) { alert(`Привет, ${name}!`); } setTimeout(sayHello, 3000, 'Василий'); // Привет, Василий!
Пример, с использованием в анонимной функции:
setTimeout(function (name) { alert(`Привет, ${name}!`); }, 3000, 'Василий');
В и можно также вместо функции передавать строку с кодом, который нужно выполнить через определённый интервал времени. Но этот вариант использовать не рекомендуется по тем же причинам, что и функцию .
Если функция по каким-то причинам не работает, то проверьте действительно ли вы передаёте ссылку на функцию, а неё результат:
function sayHello() { console.log('Привет!'); } // передаём в setTimeout не ссылку на функцию sayHello, а результат её вызова setTimeout(sayHello(), 3000);
Метки для break/continue
Бывает, нужно выйти одновременно из нескольких уровней цикла сразу.
Например, в коде ниже мы проходимся циклами по i и j , запрашивая с помощью prompt координаты (i, j) с (0,0) до (2,2) :
Нам нужен способ остановить выполнение если пользователь отменит ввод.
Обычный break после input лишь прервёт внутренний цикл, но этого недостаточно. Достичь желаемого поведения можно с помощью меток.
Метка имеет вид идентификатора с двоеточием перед циклом:
Вызов break в цикле ниже ищет ближайший внешний цикл с такой меткой и переходит в его конец.
В примере выше это означает, что вызовом break outer будет разорван внешний цикл до метки с именем outer , и управление перейдёт со строки, помеченной (*) , к alert(‘Готово!’) .
Можно размещать метку на отдельной строке:
Директива continue также может быть использована с меткой. В этом случае управление перейдёт на следующую итерацию цикла с меткой.
Метки не дают возможности передавать управление в произвольное место кода.
Например, нет возможности сделать следующее:
Вызов break/continue возможен только внутри цикла, и метка должна находиться где-то выше этой директивы.
Цикл for
Данный цикл в основном используется когда известно точное количество повторений. Этот цикл ещё называют циклом со счётчиком.
Синтаксис цикла «for»:
for (инициализация; условие; финальное выражение) { /* тело цикла */ }
Основные части конструкции цикла «for»:
- инициализация — это выражение, которое выполняется один раз перед выполнением цикла; обычно используется для инициализации счётчика;
- условие — это выражение, истинность которого проверяется перед каждой итерацией; если выражение вычисляется как истина, то выполняется итерация; в противном случае цикл «for» завершает работу;
- финальное выражение — это выражение, которое выполняется в конце каждой итерации; обычно используется для изменения счетчика;
- тело цикла — инструкции, выполнение которых нужно повторять.
Рассмотрим пример цикла, который выведет в консоль числа от 1 до 8:
// цикл «for» от 1 до 8, с шагом 1 for (var i = 1; i <= 8; i++) { console.log(i); }
В этом примере:
- инициализация: (объявление переменной и присвоение ей значения 1);
- условие выполнения цикла: (пока значение переменной меньше или равно 8);
- финальное выражение, которое нужно выполнять в конце каждой итерации: (увеличение значение переменной на 1);
- инструкция, которую нужно выполнять: (выведение значения счётчика в консоль).
При этом если тело цикла состоит из одной инструкции, то её можно не заключать в фигурные скобки.
Таким образом, пример, приведённый выше, можно записать ещё так:
// цикл «for» от 1 до 8, с шагом 1 for (var i = 1; i <= 8; i++) console.log(i);
Необязательные части цикла цикла «for».
В «for» все части цикла являются не обязательными.
Например, можно пропустить выражение инициализации:
var i = 1; // цикл «for» for (; i <= 8; i++) { console.log(i); }
В этом случае инициализацию переменной можно вынести за пределы цикла.
Условие в «for» тоже является не обязательным. Без условия цикл будет выполняться бесконечное количество раз. В этом случае чтобы его прервать (выйти из цикла) необходимо использовать инструкцию .
// цикл «for» for (var i = 1; ; i++) { if (i >= 8) { // условие прерывания цикла break; } console.log(i); }
Финальное выражение в «for» также является не обязательным. Счётчик цикла в этом случае можно, например, изменять в теле.
// цикл «for» for (var i = 1; i <= 8; ) { console.log(i); i++; // увеличение счетчика на 1 }
В «for» можно вообще опустить 3 выражения (бесконечный цикл):
var i = 1; // цикл «for» for (;;) { if (i >= 8) { break; } console.log(i); i++; }
Кроме этого, в качестве тела цикла «for» можно использовать пустое выражение (). Это используется, когда вам не нужно выполнять ни одной инструкции.
Например:
var arrA = , arrB = []; for (i = 0; i < arrA.length; arrB = arrA / 2) ; console.log(arrB); //
Пустое выражение в этом случае рекомендуется дополнительно снабжать комментарием:
// сумма чисел в массиве var arr = ; for (var i = 0, length = arr.length, sum = 0; i < length; sum += arr) /* пустое выражение */ ; // выведем сумму чисел в консоль: console.log(sum); // 12
Пример использования цикла «for» для перебора элементов массива:
var arr = ; // массив for (var i = 0, length = arr.length; i < length; i++) { console.log(arr); }
Пример, в котором выведем таблицу умножения в консоль. Для реализации этого примера будем использовать вложенные циклы.
var output = ''; for (var i = 1; i <= 9; i++) { for (var j = 1; j <= 9; j++) { output += ' ' + i * j; if (i * j < 10) { output += ' '; } } console.log(output); output = ''; }
Цикл называется вложенным, если он находится в теле другого цикла.
Приоритет операторов
В том случае, если в выражении есть несколько операторов – порядок их выполнения определяется приоритетом, или, другими словами, существует определённый порядок выполнения операторов.
Из школы мы знаем, что умножение в выражении выполнится раньше сложения. Это как раз и есть «приоритет». Говорят, что умножение имеет более высокий приоритет, чем сложение.
Скобки важнее, чем приоритет, так что, если мы не удовлетворены порядком по умолчанию, мы можем использовать их, чтобы изменить приоритет. Например, написать .
В JavaScript много операторов. Каждый оператор имеет соответствующий номер приоритета. Тот, у кого это число больше, – выполнится раньше. Если приоритет одинаковый, то порядок выполнения – слева направо.
Отрывок из таблицы приоритетов (нет необходимости всё запоминать, обратите внимание, что приоритет унарных операторов выше, чем соответствующих бинарных):
Приоритет | Название | Обозначение |
---|---|---|
… | … | … |
17 | унарный плюс | |
17 | унарный минус | |
16 | возведение в степень | |
15 | умножение | |
15 | деление | |
13 | сложение | |
13 | вычитание | |
… | … | … |
3 | присваивание | |
… | … | … |
Так как «унарный плюс» имеет приоритет , который выше, чем у «сложения» (бинарный плюс), то в выражении сначала выполнятся унарные плюсы, а затем сложение.
Цикл for/in
Цикл for/in использует ключевое слово for, но он в корне отличается от обычного цикла for. Цикл for/in имеет следующий синтаксис:
for (переменная in объект) { инструкция }
В качестве переменной здесь обычно используется имя переменной, но точно так же можно использовать инструкцию var, объявляющую единственную переменную. Параметр объект — это выражение, возвращающее объект. И как обычно, инструкция — это инструкция или блок инструкций, образующих тело цикла.
Для обхода элементов массива естественно использовать обычный цикл for:
Инструкция for/in так же естественно позволяет выполнить обход свойств объекта:
Чтобы выполнить инструкцию for/in, интерпретатор JavaScript сначала вычисляет выражение объект. Если оно возвращает значение null или undefined, интерпретатор пропускает цикл и переходит к следующей инструкции. Если выражение возвращает простое значение, оно преобразуется в эквивалентный объект-обертку. В противном случае выражение возвращает объект. Затем интерпретатор выполняет по одной итерации цикла для каждого перечислимого свойства объекта. Перед каждой итерацией интерпретатор вычисляет значение выражения, сохраняет его в переменной и присваивает ему имя свойства (строковое значение).
Обратите внимание, что переменная в цикле for/in может быть любым выражением, возвращающим значение, которое можно использовать слева от оператора присваивания. Это выражение вычисляется в каждой итерации цикла, т.е
каждый раз оно может возвращать разные значения. Например, чтобы скопировать имена всех свойств объекта в массив, можно использовать следующий цикл:
В действительности цикл for/in может совершать обход не по всем свойствам объекта, а только по перечислимым свойствам. Многочисленные встроенные методы, определяемые в базовом языке JavaScript, не являются перечислимыми. Например, все объекты имеют метод toString(), но цикл for/in не перечислит свойство toString. Кроме встроенных методов также не являются перечислимыми многие другие свойства встроенных объектов. При этом все свойства и методы, определяемые пользователем, являются перечислимыми. Унаследованные свойства, которые были определены пользователем, также перечисляются циклом for/in.
Если в теле цикла for/in удалить свойство, которое еще не было перечислено, это свойство перечислено не будет. Если в теле цикла создать новые свойства, то обычно такие свойстве не будут перечислены. (Однако некоторые реализации могут перечислять унаследованные свойства, добавленные в ходе выполнения цикла.)
Цикл while()
Цикл while() называют еще циклом с предусловием. Это значит, что вы записываете в скобках после ключевого слова while некое условие, которое возвращает либо , либо . Если возвращается , цикл выполняется, если же , то нет. Синтаксис этого цикла таков:
Цикл while()
JavaScript
while( условие ){
//код цикла
операция 1;
…
операция n;
}
1 2 3 4 5 6 |
while(условие){ //код цикла операция1; … операцияn; } |
Если переводить JavaScript-код на русский язык, то смысл цикла while можно выразить такой фразой: пока (while) выполняется условие, мы будем делать некоторые операции.
Вполне возможна ситуация, когда ваш код не выполнится ни разу. Например, вам нужно подсчитать сумму чисел в заданном пользователем диапазоне. Рассмотрим вариант кода для этого с использованием полей формы типа :
Использование цикла while для подсчете чисел в заданном диапазоне
JavaScript
<form name=»numbers»>
<p>
<label for=»from»>От числа</label> <input type=»number» min=»1″ max=»50″ value=»1″ id=»from»>
</p>
<p>
<label for=»to»>До числа</label> <input type=»number» min=»1″ max=»50″ value=»5″ id=»to»>
</p>
<p><input type=»button» value=»Подсчитать» id=»countBtn»></p>
</form>
<script>
document.numbers.countBtn.onclick = countNumbers;
function countNumbers () {
let from = +document.numbers.from.value,
to = +document.numbers.to.value;
if(from > to) {
let temp = from;
from = to;
to = temp;
}
let sum = from;
while(to>from){
from++;
sum += from;
}
alert(sum);
}
</script>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<form name=»numbers»> <p> <label for=»from»>Отчисла<label><input type=»number»min=»1″max=»50″value=»1″id=»from»> <p> <p> <label for=»to»>Дочисла<label><input type=»number»min=»1″max=»50″value=»5″id=»to»> <p> <p><input type=»button»value=»Подсчитать»id=»countBtn»><p> <form> <script> document.numbers.countBtn.onclick=countNumbers; functioncountNumbers(){ let from=+document.numbers.from.value, to=+document.numbers.to.value; if(from>to){ let temp=from; from=to; to=temp; } let sum=from; while(to>from){ from++; sum+=from; } alert(sum); } |
В этом примере цикл не выполнится ни разу в том случае, если значения начального и конечного чисел совпадут. Если же первое число будет больше, чем второе, мы поменяем их местами и цикл выполнится, как нужно.
Попробуйте сами:
Поскольку условие цикла while() должно вернуть либо , либо , мы можем использовать в нем диалоговое окно confirm(), которое как раз возвращает одно из этих логических значений в зависимости от выбора пользователя.
Использование диалогового окна confirm() в цикле while()
JavaScript
const prediction = ;
while (confirm(«Хотите получить предсказание»)) {
let rand = Math.floor(Math.random() * prediction.length);
alert(prediction);
}
1 2 3 4 5 6 7 8 |
constprediction=»У вас сегодня удачный день»,»Вам нужно задуматься о вашем выборе», «Сегодня вас ждет сюрприз»,»Вы — любимчик удачи»,»Попробуйте еще раз»,»Азартные игры не для вас», «Учите JavaScript — и вас ждет успех»,»Пора сделать зарядку»,»Перерыв на кофе-чай-печеньки сейчас будет кстати», «Пора выбросить мусор из квартиры»,»У вас отличный вкус»,»Нечего заглядываться на чужих жен»,»Пора поработать»; while(confirm(«Хотите получить предсказание»)){ let rand=Math.floor(Math.random()*prediction.length); alert(predictionrand); } |
Давайте немножко погадаем:
Получить предсказание
Примечание: цикл while — это тот цикл, с помощью которого лучше всего обычно получается «подвесить» браузер. Т.е. вы можете таким образом сформулировать условие в нем, что оно всегда будет возвращать , соответственно, цикл будет бесконечным и будет замедлять работу браузера.
Цикл for…of (новинка в ES6)
Цикл появился в стандарте ES6. Предназначен он для перебора итерируемых объектов, т.е. объектов, в которых реализован метод . Этот метод ещё называют итератором. Именно его и использует цикл для перебора объектов.
Метод имеется у , , , , , и других объектов.
Пример использование цикла для посимвольного перебора строки:
// переменная, содержащая строку let str = 'Новый'; // посимвольный перебор строки for (let char of str) { console.log(char); } // в консоль будет выведено: "Н", "о", "в", "ы", "й"
Пример использование цикла для перебора коллекции DOM-элементов:
let elements = document.querySelectorAll('p'); for (let element of elements) { console.log(element); }
Пример использование цикла для перебора массива:
// массив let superHeroes = ; // перебор массива for (let value of superHeroes) { console.log(value); } // в консоль будет выведено: "Iron Man", "Thor", "Hulk"
Чем цикл for…of отличается от for…in
Первое отличие цикла от заключается в том, что он может применяться только для итерируемым объектов, т.е. объектов, в которых реализован итератор (). Цикл итератор не использует. Он предназначен для перебора любых объектов.
Второе отличие заключается в том, что цикл перебирает объект так, как это определено в итераторе. Например, в итератор реализован так, что цикл пройдёт только по значениям в массиве и не будет включать в перебор другие (не индексные) свойства. Цикл организован по-другому, он перебирает все перечисляемые свойства (имена ключей) объекта, в том числе и наследуемые.
Рассмотрим эти отличия. Для этого возьмём предыдущий пример и добавим к нему пользовательское свойство, например, и установим ему значение .
let superHeroes = ; superHeroes.hero = 'Wasp';
При использовании он переберёт все значения этого массива:
// цикл for...of for (let value of superHeroes) { console.log(value); } // в консоль будет выведено: "Iron Man", "Thor", "Hulk"
При использовании он переберёт все перечисляемые имена ключей этого объекта:
// цикл for...in for (let key in superHeroes) { console.log(key); } // в консоль будет выведено: 0, 1, 2, "hero"
Чтобы получить значение ключа по его имени можно воспользоваться квадратными скобками:
// цикл for...in for (let key in superHeroes) { console.log(superHeroes); } // в консоль будет выведено: "Iron Man", "Thor", "Hulk", "Wasp"
Самостоятельное создание итератора для объекта
Рассмотрим ещё один пример. В этом примере мы самостоятельно определим как должен итерироваться объект. Для этого создадим объект и определим ему итератор.
Создание итератора начинается с добавления к объекту специального метода. Этот метод необходимо спроектировать так, чтобы он возвращал значения последовательно (одно за другим). Название методу согласно стандарту необходимо определить с помощью символа . Итератор должен возвращать всего один метод . Этот метод в свою очередь тоже должен возвращать объект, состоящий из 2 свойств: и . Ключ — булевый. Он определяет есть ли ещё значения в последовательности ( — да, — нет). Ключ должен содержать следующее значение последовательности.
let car = { color: 'black', brand: 'Ford', // создадим итератор, используя символ () { // получим имена перечисляемых свойств объекта const keys = Object.keys(this); // создадим переменную (текущий индекс последовательности) let index = 0; return { next() { let done = index >= keys.length; let value = done ? undefined : keys; return { value, done } } } } } for (let key in car) { console.log(key + ' => ' + car); } // в консоль будет выведено: color => "black", brand => "Ford"
Definition and Usage
The do/while statement creates a loop that executes a block of code once,
before checking if the condition is true, then it will repeat the loop as long
as the condition is true.
The do/while statement is used when you want to run a loop at least
one time, no matter what.
JavaScript supports different kinds of loops:
- for — loops through a block of code a number of times
- for/in — loops through the properties of an object
- for/of — loops through the values of an iterable object
- while — loops through a block of code while a specified condition is true
- do/while — loops through a block of code once, and then repeats the loop while a specified condition is true
Итого
Объекты, которые можно использовать в цикле , называются итерируемыми.
- Технически итерируемые объекты должны иметь метод .
- Результат вызова называется итератором. Он управляет процессом итерации.
- Итератор должен иметь метод , который возвращает объект , где сигнализирует об окончании процесса итерации, в противном случае – следующее значение.
- Метод автоматически вызывается циклом , но можно вызвать его и напрямую.
- Встроенные итерируемые объекты, такие как строки или массивы, также реализуют метод .
- Строковый итератор знает про суррогатные пары.
Объекты, имеющие индексированные свойства и , называются псевдомассивами. Они также могут иметь другие свойства и методы, но у них нет встроенных методов массивов.
Если мы заглянем в спецификацию, мы увидим, что большинство встроенных методов рассчитывают на то, что они будут работать с итерируемыми объектами или псевдомассивами вместо «настоящих» массивов, потому что эти объекты более абстрактны.
создаёт настоящий из итерируемого объекта или псевдомассива , и затем мы можем применять к нему методы массивов. Необязательные аргументы и позволяют применять функцию с задаваемым контекстом к каждому элементу.