Циклы позволяют в зависимости от определенных условий выполнять некоторое действие множество раз. В JavaScript имеются следующие виды циклов:
for
for..in
for..of
while
do..while
Цикл for имеет следующее формальное определение:
for ([инициализация счетчика]; [условие]; [изменение счетчика]){ // действия }
Например, используем цикл for для перебора чисел от 0 до 4:
for(let i = 0; i<5; i++){ console.log(i); } console.log("Конец работы");
Первая часть объявления цикла - let i = 0
- создает и инициализирует счетчик - переменную i. И перед выполнением цикла ее
значение будет равно 0. По сути это то же самое, что и объявление переменной.
Вторая часть - условие, при котором будет выполняться цикл: i<5
. В данном случае цикл будет выполняться, пока значение i не достигнет 5.
Третья часть - i++
- приращение счетчика на единицу.
То есть при запуске переменная i
равна 0. Это значение отвечает условию i<5
, поэтому будет выполняться блок цикла, а именно строка кода
console.log(i);
После выполнения блока цикла выполняется треться часть объявления цикла - приращение счетчика. То есть переменная i сановится равной 1. Это значение также отвечает условию, поэтому блок цикла снова выполняется. Таким образом, блок цикла сработает 5 раз, пока значение i не станет равным 5. Это значение НЕ отвечает условию, поэтому произойдет выход из цикла. И управление программой перейдет к инструкциям, которые идут после блока цикла. Консольный вывод программы:
0 1 2 3 4 Конец работы
Каждое отдельное повторение цикла называется итерацией. Таким образом, в данном случае сработают 5 итераций.
При этом необязательно увеличивать счетчик на единицу, можно производить с ним другие действия, например, уменьшать на единицу:
for(let i = 10; i > 5; i--){ console.log(i); }
В данном случае на консоль выводится числа от 10 до 6.
Или увеличим счетчик на 2:
for(let i = 0; i < 10; i+=2){ console.log(i); }
Здесь выводятся на консоль все четные числа от 0 до 8
При этом можно опускать различные части объявления цикла:
let i = 0; for(; i < 60;){ console.log(i); i = i + 10; }
В данном случае переменная i определена вне цикла. В самом объявлении цикла есть только условие, остальные две части отсутствуют. Изменение переменной происходит в самом блоке цикла: оно увеличивается на 10. В итоге на консоль будут выведены числа 0, 10, 20, 30, 40, 50.
Счетчик удобно использовать как индекс элементов массива и таким образом перебирать массив:
const people = ["Tom", "Sam", "Bob"]; for(let i=0; i < 3; i++){ console.log(people[i]); }
Консольный вывод браузера:
Tom Sam Bob
При необходимости можно использовать несколько счетчиков:
for(let i = 1, j=1; i < 5, j < 4; i++, j++){ console.log(i + j); } // 1 итерация: i=1, j=1; i + j = 2 // 2 итерация: i=2, j=2; i + j = 4 // 3 итерация: i=3, j=3; i + j = 6
Здесь теперь используются два счетчика и два условия. Рассмотрим пошагово, что здесь происходит:
Первая итерация. Начальные значения переменных i и y:
i=1, j=1;
Для каждой переменной установлены свои условия. И вначале начальные значения переменных соответствуют этим условиям:
i < 5, j < 4;
В блоке цикла выводится сумма этих переменных. И дальше значения обоих переменных увеличиваются на единицу. Они становятся равны
i=2, j=2;
Эти значения также соответствуют условиям, поэтому выполняется вторая итерация
Вторая итерация. Значения переменных i и y:
i=2, j=2;
После выполнения блока цикла значения обоих переменных увеличиваются на единицу. Они становятся равны
i=3, j=3;
Эти значения также соответствуют условиям, поэтому выполняется третья итерация
Третья итерация. Значения переменных i и y:
i=3, j=3;
После выполнения блока цикла значения обоих переменных увеличиваются на единицу. Они становятся равны
i=4, j=4;
Значение переменной i
соответствует условию i < 5
, однако значение переменной j (4) НЕ соответствует условию
j < 4
. Поэтому происходит выход из цикла. Его работа завершена.
Стоит отметит, что третья часть цикла, где обычно происходит изменение счетчика в реальности представляет произвольное действие, которое выполняется после завершения цикла. Так, мы можем написать следующим образом:
for(let i = 0; i < 5; console.log(i++)); console.log("Конец работы");
Здесь не определено блока цикла, а сами действия цикла определены в третьей части заголовка цикла - console.log(i++)
Аналогично в первой части определения цикла - инициализации мы можем выполнять некоторые действия, а не обязательно только объявление счетчика:
let i=0; for(console.log("Init"); i < 5; i++){ console.log(i); }
Здесь определение счетчика вынесено вне цикла, а в инициализационной части цикла на консоль выводится строка. Вывод браузера:
Init 0 1 2 3 4
Одни циклы могут внутри себя содержать другие:
for(let i=1; i <= 5; i++){ for(let j = 1; j <=5; j++){ console.log(i * j); } }
Здесь один цикл включается в себя другой. ВО внешнем цикле определяется переменная i. Вначале она равна 1 и это значение соответствует условию цикла
(i <=5
), поэтому будет выполняться блок цикла, который содержит внутренний цикл.
Во внутреннем цикле определяется переменная-счетчик j, которая изначально равна 1, и потом внутренний цикл выполняет 5 итераций, пока переменная j не станет равна 5.
После того, как блок внешнего цикла завершен, переменная i увеличивается на 1 и становится равной 2, что опять же соответствует условию. И снова выполняется блок внешнего цикла. В этом блоке снова выполняются пять итераций внутреннего цикла. И так далее. В итоге внутренний цикл будет выполняться 25 раз.
Используя вложенные циклы и несколько счетчиков можно перебирать многомерные массивы:
const people = [["Tom", 39], ["Sam", 28],["Bob", 42]]; for(let i=0; i < 3; i++){ // перебираем двухмерный массив for(let j=0; j < 2; j++){ // перебираем вложенные массивы console.log(people[i][j]); } console.log("================="); // для разделения элементов }
Здесь массив people представляет двухмерный массив из 3-х элементов, где каждый элемент представляет, в свою очередь, подмассив из 2-х элементов - условно имени и возраста пользователя. Во внешнем цикле определяем счетчик i для прохода по всем подмассивам в двухмерном массиве people, а во внутреннем цикле определяем счетчик j для прохода по всем элементам каждого подмассива. Консольный вывод:
Tom 39 ================= Sam 28 ================= Bob 42 =================
Цикл while выполняется до тех пор, пока некоторое условие истинно. Его формальное определение:
while(условие){ // действия }
Опять же выведем с помощью while числа от 1 до 5:
let i = 1; while(i <=5){ console.log(i); i++; }
Цикл while здесь будет выполняться, пока значение i не станет равным 6.
В цикле do сначала выполняется код цикла, а потом происходит проверка условия в инструкции while. И пока это условие истинно, цикл повторяется. Например:
let i = 1; do{ console.log(i); i++; }while(i <= 5)
Здесь код цикла сработает 5 раз, пока i не станет равным 5. При этом цикл do гарантирует хотя бы однократное выполнение действий, даже если условие в инструкции while не будет истинно.
Иногда бывает необходимо выйти из цикла до его завершения. В этом случае мы можем воспользоваться оператором break:
for(let i=1; i <= 6; i++){ if(i===4) break; console.log(i); } console.log("Конец работы");
Данный цикл увеличивает переменную i c 1 до 6 включая, то есть согласно условию цикла блок цикла должен выполняться 6 раз, то есть поизвести 6 итераций.
Однако поскольку в блоке цикла происходит поверка if(i===4) break;
, то, когда значение переменной i достигнет 4, то данное условие
прервет выполнение цикла с помощью оператора break. И цикл заершит работу.
1 2 3 Конец работы
Если нам надо просто пропустить итерацию, но не выходить из цикла, мы можем применять оператор continue. Например, изменим предыдущий пример, только вместо break
используем оператор continue:
for(let i=1; i <= 6; i++){ if(i===4) continue; console.log(i); } console.log("Конец работы");
В этом случае, когда значение переменная i станет равной 4 , то выражение i===4
возвратит true
, поэтому будет выполняться конструкция
if(i===4) continue;
. С помощью оператора continue она завершит текущую итерацию,
далее идущие инструкции цикла не будут выполняться, а произойдет переход к следующей итерации:
1 2 3 5 6 Конец работы
Цикл for..in предназначен главным образом для перебора объектов. Его формальное определение:
for (свойство in объект) { // действия }
Этот цикл перебирает все свойства объекта. Например:
const person = {name: "Tom", age: 37}; for(prop in person){ console.log(prop); }
Здесь перебирается объект person, который имеет два свойства - name и age. Соответственно на консоли мы увидим:
name age
Получив свойтсва и используя специальный синтаксис объект[свойство]
, мы можем получить значение каждого свойства:
const person = {name: "Tom", age: 37}; for(prop in person){ console.log(prop, person[prop]); }
Консольный вывод:
name Tom age 37
Цикл for...of предназначен для перебора наборов данных. Например, строка представляет фактически набор символов. И мы можем перебрать ее с помощью данного цикла:
const text = "Hello"; for(char of text){ console.log(char); }
В итоге цикл перебирает все символы строки text
и помещает каждый текущий символ в переменную ch
, значение которой затем
выводится на консоль.
H e l l o
Другим примером может быть перебор массива:
const people = ["Tom", "Sam", "Bob"]; for(const person of people) { console.log(person); }
В данном случае цикл перебирает элементы массива people. Каждый элемент последовательно помещается в константу person
. И далее мы можем вывести ее значение на консоль:
Tom Sam Bob