Циклы: while, do..while и for

Понадобилось вывести числа от 1 до 100 – копировать сто строк? Программы для того и существуют, чтобы повторять за нас. Цикл – это блок кода плюс правило «продолжать ли». Каждый повтор тела называют итерацией – или, по-русски, кругом; в уроке оба слова значат одно и то же, а «итерация» будет встречаться вам в документации и чужом коде постоянно.

Простейший – while: «пока условие истинно – выполняй тело». Как с посудой: пока в раковине есть тарелки – мой следующую. Условие проверяется перед каждым кругом.

Повторение без копипасты

Сто строк вывода – это не сто console.log.

while.jsjs
let i = 1;while (i <= 3) {  console.log(i);  // без этой строки цикл никогда не закончился бы  i++;}
Консоль
1
2
3
Круги while – по шагам
let i = 1;
Счётчик создан: i = 1.
while (i <= 3) {
console.log(i);
i++;
}
console.log("после цикла");

Внимание на строку i++: тело обязано приближать конец – иначе условие никогда не станет ложным, и программа зависнет в вечном цикле. К этой ловушке вернёмся ниже отдельно.

У while есть брат do..while: он проверяет условие после тела, поэтому тело выполнится хотя бы один раз – «сначала попробуй, потом решай, пробовать ли ещё». Нужен редко, но метко.

do-while.jsjs
do {  console.log('хотя бы раз');} while (false);
Консоль
хотя бы раз
Условие ложно с самого начала – но тело уже успело выполниться.

for: всё о цикле в одной строке

Весь план повторения – старт, граница, шаг – умещается в одной строке заголовка.

for.jsjs
for (let i = 1; i <= 3; i++) {  console.log(i);}
Консоль
1
2
3
То же, что while выше, – но всё о счётчике собрано в заголовке.

Цикл «от и до» встречается так часто, что у него есть своя форма – for. В скобках через точку с запятой три части: старт (выполнится один раз перед началом), условие (проверяется перед каждым кругом), шаг (выполняется после каждого круга).

Переменная из let i = 1 живёт только внутри цикла – снаружи её нет, и это хорошо: счётчик никому не мешает. Имя i – сокращение от index: так счётчик называют со времён первых языков программирования, и любой программист узнаёт его с одного взгляда. Во вложенных циклах берут следующие буквы алфавита – j, k.

Три части заголовка отвечают на вопросы: с чего начать, когда остановиться, как двигаться.
Части for в работе – по шагам
for (let i = 1; i <= 3; i++) {
Старт выполняется один раз: создаётся i = 1.
console.log(i);
}

Когда что брать? for – когда число кругов известно заранее: пройти от 1 до 100, повторить ровно десять раз. while – когда заранее неизвестно, сколько повторять: крутите, пока условие не изменится. Есть счётчик – пишите for; есть только условие – while:

first-digit.jsjs
let code = 7245;while (code >= 10) {  // отбрасываем последнюю цифру  code = Math.floor(code / 10);}console.log(code);
Консоль
7
Первая цифра числа: сколько кругов – зависит от длины числа, заранее её не знаешь.

Части заголовка можно пропускать

Любую из трёх частей можно оставить пустой – но обе точки с запятой обязаны стоять на местах. Старт пропускают, когда счётчик уже создан раньше:

skip-start.jsjs
let i = 1;for (; i <= 3; i++) {  console.log(i);}
Консоль
1
2
3
Старт пуст – счётчик уже существует; его точка с запятой всё равно на месте.

Шаг оставляют пустым, когда переменную двигает само тело:

skip-step.jsjs
for (let n = 1; n < 8; ) {  n *= 2;  // переменную двигает тело  console.log(n);}
Консоль
2
4
8
Шаг пуст – удвоение происходит внутри тела цикла.

Пустыми могут быть и все три части сразу. Пустое условие считается истинным, так что for (;;) – намеренно бесконечный цикл, о них дальше:

forever.jsjs
for (;;) {  // тело выполняется без конца}
Цикл без старта, условия и шага – обе точки с запятой по-прежнему обязательны.

break: досрочный выход

break немедленно выходит из цикла целиком: остаток тела не выполняется, новые круги не начинаются, программа продолжается со строки после цикла. Работает в любом цикле – while, do..while, for. Первая типичная ситуация – поиск: нашли подходящее, дальше перебирать бессмысленно:

search.jsjs
const secret = 4;for (let i = 1; i <= 10; i++) {  if (i === secret) {    console.log('найдено: ' + i);    // дальше перебирать бессмысленно    break;  }}
Консоль
найдено: 4
Без break цикл докрутил бы до десяти, хотя ответ найден на четвёртом круге.

Вторая ситуация – цикл, задуманный без конца: условие while (true) истинно всегда, и единственная дверь наружу – break:

countdown.jsjs
let timer = 5;while (true) {  timer--;  // единственная дверь наружу  if (timer === 0) break;}console.log('старт!');
Консоль
старт!

continue: пропуск круга

continue мягче: он пропускает остаток текущего круга и переходит к следующему. Цикл не останавливается – просто один круг закончился досрочно. В for шаг при этом выполняется как обычно.

Главный сценарий – фильтрация: обработать только подходящие элементы. Условие с continue в начале тела читается как охранник на входе: «этот не подходит – следующий», а весь код ниже остаётся ровным, без лишней вложенности.

even-only.jsjs
for (let i = 1; i <= 6; i++) {  // нечётное – пропускаем круг  if (i % 2 !== 0) continue;  console.log(i);}
Консоль
2
4
6
Охранник на входе: нечётные круги заканчиваются досрочно, чётные доходят до печати.
skip-one.jsjs
for (let i = 1; i <= 4; i++) {  // выпадает только тройка  if (i === 3) continue;  console.log(i);}console.log('готово');
Консоль
1
2
4
готово
Выпал только круг с тройкой – остальные дошли до печати, и цикл дожил до конца.

Бесконечные циклы

Цикл бесконечен, когда условие никогда не становится ложным. Чаще всего это ошибка: забыли i++, двинули не ту переменную или написали условие, которое не зависит от тела. Программа не падает – она молча работает без конца, и вкладка браузера виснет.

Но бесконечный цикл бывает и намеренным: while (true) или for (;;) пишут, когда число кругов заранее неизвестно, а из цикла выходят изнутри через уже знакомый break.

Бесконечный цикл: приём и ошибка
Намеренно бесконечный: выход через break
let thickness = 0.1;  // лист бумаги, ммlet folds = 0;while (true) {  thickness *= 2;  // сложили пополам  folds++;  // толще человеческого роста  if (thickness > 1700) break;}// 15 – а не «семь раз», как в известном мифеconsole.log(folds);
Забытый шаг: цикл никогда не закончится
let i = 1;while (i <= 3) {  // i не меняется – условие истинно всегда  console.log(i);}

// теперь вы знаете

  1. while повторяет, пока условие истинно; do..while проверяет после тела
  2. for – когда число кругов известно заранее; while – когда есть только условие
  3. for собирает старт, условие и шаг в одной строке; любую часть можно оставить пустой
  4. break выходит из цикла целиком – поиск и выход из бесконечных
  5. continue пропускает остаток круга – фильтрация без вложенности
  6. for (;;) и while (true) – намеренно бесконечные циклы с выходом через break
  7. Бесконечный цикл по ошибке – условие, в котором ничего не меняется

Проверьте себя

Сколько строк напечатает код?

let n = 100;
do {
console.log(n);
n++;
} while (n < 10);

Сколько строк напечатает цикл?

for (let i = 0; i < 5; i += 2) {
console.log(i);
}

Что делает запись for (;;) { ... }?

переключают уроки · не работают при фокусе в полях ввода