Назад
Frontend

Циклы в JavaScript

Циклы позволяют выполнять код повторно. Знание всех видов циклов и когда их применять - базовый навык фронтендера.

Виды циклов

  • for - известно количество итераций
  • while - условие, количество итераций неизвестно
  • do...while - нужно выполнить тело хотя бы раз
  • for...of - перебор итерируемых объектов (массивы, строки)
  • for...in - перебор ключей объекта
  • forEach - перебор массива без возможности прервать

1. for - самый узнаваемый

for (let i = 0; i < 5; i++) {
  console.log(i); // 0, 1, 2, 3, 4
}

Структура: for (инициализация; условие; шаг)

Пример с массивом:

const fruits = ['яблоко', 'банан', 'вишня'];

for (let i = 0; i < fruits.length; i++) {
  console.log(`${i}: ${fruits[i]}`);
}
// 0: яблоко
// 1: банан
// 2: вишня

2. while - пока условие истинно

let count = 0;

while (count < 3) {
  console.log(count); // 0, 1, 2
  count++;
}

Реальный пример - ожидание данных:

let attempts = 0;
let data = null;

while (!data && attempts < 5) {
  data = fetchData(); // попытка получить данные
  attempts++;
}

3. do…while - выполнить хотя бы раз

let num;

do {
  num = Math.random();
  console.log(num);
} while (num < 0.5); // повторяем, пока число меньше 0.5

Отличие от while: тело выполнится минимум один раз, даже если условие сразу ложно.

4. for…of - перебор значений

Работает с: массивы, строки, Map, Set, NodeList.

const colors = ['red', 'green', 'blue'];

for (const color of colors) {
  console.log(color);
}
// red, green, blue

С индексом через entries():

for (const [index, color] of colors.entries()) {
  console.log(`${index}: ${color}`);
}
// 0: red, 1: green, 2: blue

Перебор строки:

for (const char of 'hello') {
  console.log(char); // h, e, l, l, o
}

5. for…in - перебор ключей объекта

const user = { name: 'Алина', age: 25, city: 'Москва' };

for (const key in user) {
  console.log(`${key}: ${user[key]}`);
}
// name: Алина
// age: 25
// city: Москва

Осторожно: for...in обходит и унаследованные свойства. Используй hasOwnProperty для проверки:

for (const key in user) {
  if (user.hasOwnProperty(key)) {
    console.log(key);
  }
}

6. forEach - метод массива

const nums = [1, 2, 3];

nums.forEach((num, index) => {
  console.log(`[${index}] = ${num}`);
});
// [0] = 1, [1] = 2, [2] = 3

Ограничения forEach:

  • Нельзя прервать через break
  • Не возвращает новый массив (для этого - map)
  • Не работает с async/await как ожидается

Управление циклом: break и continue

// break - выход из цикла
for (let i = 0; i < 10; i++) {
  if (i === 5) break;
  console.log(i); // 0, 1, 2, 3, 4
}

// continue - пропустить итерацию
for (let i = 0; i < 5; i++) {
  if (i === 2) continue;
  console.log(i); // 0, 1, 3, 4
}

Частые ошибки

// Бесконечный цикл - забыли инкремент
while (true) {
  console.log('ops...'); // зависнет браузер
}

// for...in на массиве - плохая практика
const arr = [10, 20, 30];
for (const key in arr) {
  console.log(key); // "0", "1", "2" - строки, не числа!
}

// async в forEach не работает как ожидается
const ids = [1, 2, 3];
ids.forEach(async (id) => {
  const data = await fetch(`/api/${id}`); // не ждет завершения!
});

// Правильно - for...of с async/await
for (const id of ids) {
  const data = await fetch(`/api/${id}`); // работает корректно
}

Шпаргалка: что выбрать

Массив, нужен индекс?          -> for (классика)
Массив, только значения?       -> for...of
Массив, без break/continue?    -> forEach
Объект, ключи?                 -> for...in
Условие, не массив?            -> while
Хотя бы одно выполнение?      -> do...while
Async/await внутри цикла?      -> for...of (НЕ forEach!)