Цикл for и перебор коллекций

ветвления≈ 7 минут

Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.

Цикл — это способ сказать «повтори ещё раз», не переписывая код руками. В JavaScript есть три разных for: один считает, второй достаёт значения, третий — ключи, и путать их больно.

Разделы темы:·

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

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Порядок такой: let i = 0 → проверка i < 3 → тело → i++ → снова проверка. Как только условие даёт false, цикл заканчивается и выполнение идёт дальше. Переменную i видно только внутри цикла — она объявлена через let прямо в заголовке.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Такой for берут, когда нужен именно номер шага: идти через один, считать назад, пройти половину массива. Если номер не нужен — есть варианты приятнее.

for..of проходит по значениям коллекции и отдаёт их по одному. Никаких i, никакой длины, никакой возможности промахнуться мимо границы массива.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Переменную объявляют через const: на каждой итерации она создаётся заново, так что переприсваивать её обычно не нужно. Работает for..of не только с массивами — строка тоже перебирается посимвольно, и Map с Set тоже умеют.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

У массива есть метод entries() — он выдаёт пары «индекс, значение». Пару удобно сразу разобрать по переменным в квадратных скобках, это называется деструктуризацией.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

for..in перебирает ключи объекта. Значение достают уже вручную — через квадратные скобки, потому что имя свойства лежит в переменной.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Для массивов for..in формально работает, но это ловушка. Во-первых, ключи приходят строками: "0", а не 0. Во-вторых, он выдаёт все перечислимые свойства, а не только элементы — если кто-то добавил массиву обычное свойство, оно тоже попадёт в перебор.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

in — ключи, of — значения. Два слова, а сколько сэкономленных часов.

Тело цикла — обычный код, значит внутри может стоять ещё один цикл. Внешний делает один шаг — внутренний успевает пройти целиком. Отсюда простое правило подсчёта: два цикла по три шага дают девять повторений тела.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Чаще всего вложенность нужна для «массива массивов» — таблицы, игрового поля, матрицы. Внешний цикл идёт по строкам, внутренний — по ячейкам строки.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Обычный break прерывает только тот цикл, в котором стоит. Чтобы выпрыгнуть из обоих, циклу дают метку — имя с двоеточием — и пишут break имя. Метки, а вместе с ними break и continue целиком, разбирает статья «break и continue: управление циклом».

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Кроме циклов у массива есть метод forEach: он сам зовёт вашу функцию для каждого элемента и передаёт в неё значение и индекс. Выглядит компактно и хорошо читается.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

У forEach есть цена: из него нельзя выйти досрочно. break там — синтаксическая ошибка, а return завершает лишь текущий вызов функции. Нужен ранний выход — берите for..of.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
СпособЧто в рукахМожно break
for (let i = 0; ...)индекс iда
for..ofзначениеда
for..inключ, всегда строкада
forEachзначение и индекснет

Практический выбор простой: перебираете значения массива — for..of; нужен хитрый шаг или номер — классический for; идёте по свойствам объекта — for..in.

  • Классический for(;;) состоит из счётчика, условия и шага; берите его, когда нужен номер итерации или нестандартный шаг.
  • for..of отдаёт значения массива, строки, Map или Set — самый частый выбор для перебора коллекции.
  • for..in перебирает ключи объекта; для массивов он опасен: ключи приходят строками и попадают лишние свойства.
  • Вложенные циклы проходят «таблицу»: внешний идёт по строкам, внутренний — по ячейкам; выйти сразу из обоих помогает метка и break имя.
  • forEach читается компактно, но прерваться в нём нельзя — там, где нужен break, используйте for..of.

1/3Что выведет этот код?
const arr = ["a", "b"];
for (const x in arr) console.log(x);

2/3Сколько раз выполнится тело цикла for (let i = 10; i > 7; i--)?

3/3Из какого перебора нельзя выйти досрочно через break?

Сумма чётных чисел

Дан массив чисел. Посчитайте сумму только чётных элементов и выведите её. Чётность проверяется остатком от деления: n % 2 === 0.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Индексы здесь не нужны — достаточно значений, поэтому берём for..of и прибавляем к сумме только те числа, у которых остаток от деления на 2 равен нулю.

jsлистинг · не запускается
Листинг только для чтения: этот код не запускается в браузере.

Считаются 8 и 10, вместе они дают 18. Через классический for вышло бы столько же строк, но пришлось бы писать nums[i] и следить за границей массива.

Таблица умножения 3×3

С помощью вложенных циклов выведите три строки таблицы умножения: в каждой — числа от i * 1 до i * 3, склеенные через пробел. Ниже показан ожидаемый вывод.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Внешний цикл отвечает за номер строки, внутренний собирает её содержимое в текстовую переменную. Печатаем строку после того, как внутренний цикл закончил работу.

jsлистинг · не запускается
Листинг только для чтения: этот код не запускается в браузере.

Метод trim() убирает лишний пробел в конце. Важная деталь: let row объявлена внутри внешнего цикла — если вынести объявление наружу, все строки склеятся в одну длинную.