Скидки до 60% и 3 курса в подарок 0 дней 00 :00 :00 Выбрать курс
Код
#База знаний

Циклы в JavaScript: какие бывают, чем различаются и зачем нужны

Объясняем на практике для тех, кто только начал изучать код.

Иллюстрация: Polina Vari для Skillbox Media

При разработке веб-приложений встречаются задачи, когда нужно выполнить одно и то же действие несколько раз подряд. Например, вывести на экран все элементы массива, перебрать список пользователей или посчитать сумму чисел от 1 до 100. Циклы в JavaScript позволяют автоматизировать такие рутинные операции и решать их гораздо быстрее, чем при копировании одних и тех же строчек кода.

Содержание


Коротко: что такое циклы и зачем они нужны

Циклы — это конструкции, которые помогают повторять заданный участок кода столько раз, сколько нужно. Они экономят время, делают программу короче и позволяют автоматизировать рутинные действия.

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

Пример:

for (let i = 0; i < 5; i++) { // Условие цикла
  console.log(i); // Вывод в консоль
}

Что делает этот код:

  • создаёт переменную i со значением 0;
  • проверяет: если i меньше 5, выводит переменную в консоль;
  • увеличивает i на 1 и повторяет;
  • как только i станет 5, цикл остановится.

Результат:

0
1
2
3
4

Какие циклы есть в JavaScript

В JavaScript есть несколько видов циклов. Они подходят для разных задач, но цель у них общая — повторять действия до тех пор, пока выполняется заданное условие. Пять основных видов циклов:

НазваниеКогда используется
forКогда вы знаете, сколько повторов нужно
whileКогда нужно повторять до тех пор, пока условие верно
do...whileКогда нужно хотя бы один раз выполнить код
for...ofКогда нужно пройтись по значениям массива или по символам строки
for...inКогда нужно пройтись по свойствам объекта

Зачем нужны циклы на практике

  • Перебор массивов и объектов. Отображение списка сообщений в чате, подсчёт общего рейтинга отзывов, проверка всех элементов на соответствие условию.
  • Автоматизация рутинных действий. Вместо копирования одинакового кода несколько раз вы пишете всего пару строк — это упрощает сопровождение и ускоряет разработку.
  • Чтение внешних данных. При работе с данными, полученными с сервера, вы можете последовательно обойти все записи и выполнить нужные действия (например, вывести их на страницу).
  • Тестирование и прототипирование. Циклы помогут быстро «сгенерировать» тестовые данные или провести однотипные проверки.

С теорией разобрались, пройдёмся по основным типам циклов в JavaScript.

Циклы while и for в JavaScript — базовый уровень

Циклы while и for очень похожи друг на друга — оба повторяют участок кода несколько раз. Цикл while считается более базовым: он состоит из исполняемого кода и условия. А цикл for — это удобная надстройка над while, которая позволяет перебрать что-то определённое количество раз.

Оператор while: повторяем до тех пор, пока условие истинно

Цикл while удобен, когда заранее неизвестно точное количество повторений, но известно условие, при котором цикл должен продолжать работу.

while (условие) {
    // Код, который будет выполняться
}

Алгоритм работы

1. Проверяется условие. Если оно истинно, цикл запускается.

2. Выполняется код внутри цикла.

3. После выполнения снова проверяется условие:

  • Если оно истинно, код запускается снова.
  • Если оно ложно, цикл останавливается, а управление передаётся следующей части программы.

Важно следить за условием: если оно никогда не становится ложным, цикл станет бесконечным.

Пример использования

Предположим, вы делаете простой to-do-список задач. У вас есть массив с задачами, и нужно вывести все задачи на страницу.

const tasks = ['Купить продукты', 'Позвонить маме', 'Подготовить проект']; // Список задач в массиве
let index = 0; // Начальный индекс элемента массива

while (index < tasks.length) { // Условие: пока не дойдём до конца массива
    console.log(`Задача №${index + 1}: ${tasks[index]}`);
    index++;
}

// Вывод в консоли:
// Задача №1: Купить продукты
// Задача №2: Позвонить маме
// Задача №3: Подготовить проект

В этом примере вы перебираете список задач из массива и выводите каждую задачу с её номером. Подобный подход используется при выводе элементов списка на веб-странице или в меню приложений.

Разберём этот пример построчно.

1. Объявление массива.

const tasks = ['Купить продукты', 'Позвонить маме', 'Подготовить проект'];

Мы создаём массив (список) задач. У него три элемента. Каждый элемент — это строка, то есть текст с названием задачи. У каждого элемента есть индекс:

  • tasks[0] — «Купить продукты».
  • tasks[1] — «Позвонить маме».
  • tasks[2] — «Подготовить проект».

2. Инициализация счётчика.

let index = 0;

Создаётся переменная index. Она будет указывать, на каком месте в массиве мы сейчас находимся. Начинаем с 0, потому что нумерация в массивах в JavaScript начинается с нуля.

3. Цикл while.

while (index < tasks.length) {

tasks.length — это количество элементов в массиве, то есть 3. Условие index < tasks.length означает «пока индекс меньше 3, продолжай выполнять цикл». Как только index станет равен 3, условие станет ложным и цикл остановится.

4. Тело цикла.

console.log(`Задача №${index + 1}: ${tasks[index]}`);

Мы выводим в консоль текст:

  • Задача №1: Купить продукты
  • Задача №2: Позвонить маме
  • Задача №3: Подготовить проект

Мы пишем index + 1, потому что хотим показать нумерацию с 1, а не с 0. tasks[index] — это текущая задача, которую мы берём из массива.

5. Шаг цикла.

index++;

После каждого вывода задачи мы увеличиваем индекс на 1. Это нужно, чтобы перейти к следующей задаче. Если этого не сделать, цикл будет бесконечным.

Когда может быть нужен цикл while на практике

  • Проверка попыток входа в систему. Допустим, вы создаёте систему, в которой пользователь может ввести пароль. У него есть несколько попыток, чтобы сделать это правильно. Если все попытки исчерпаны, доступ блокируется.
  • Количество жизней в игре. Допустим, игрок может делать ходы до тех пор, пока у него есть жизни. Когда они кончились, игра завершается.
  • Ожидание события. Представьте, что вы пишете программу, которая обрабатывает файл, например отправляет его на сервер. Вы хотите проверять статус обработки каждые несколько секунд до тех пор, пока файл не будет успешно загружен.

Цикл do…while: сначала делаем, потом проверяем

Цикл do…while всегда выполняется минимум один раз, даже если условие с самого начала ложное. Обычный while сначала проверяет условие, а потом решает, выполнять код или нет. А do…while сначала выполняет код один раз, а уже потом проверяет условие и решает, повторять ли ещё.

do {
    // Код, который выполнится хотя бы один раз
} while (условие);

Используйте do…while, например, при получении пользовательского ввода или при начальной инициализации переменных перед проверкой.

Пример использования

Представим, что вы делаете форму регистрации для вашего списка задач. Нужно убедиться, что пользователь ввёл email, который выглядит как email, — и если нет, то запрашивать ввод снова.

let email; 
// Объявляем переменную, в которую пользователь будет вводить email

const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 
// Создаём регулярное выражение — это шаблон, по которому можно проверить, похожа ли строка на email
// ^ — начало строки
// [^\s@]+ — одна или несколько букв или цифр, кроме пробелов и символа @
// @ — обязательно должен быть символ @
// [^\s@]+ — после @ снова одна или несколько букв или цифр, кроме пробелов и @
// \. — обязательно точка
// [^\s@]+ — после точки снова одна или несколько букв или цифр
// $ — конец строки

do {
    email = prompt("Введите свой email:"); 
    // Показываем пользователю окно ввода. Что бы он ни ввёл, сохраняем в переменную email
} while (!emailPattern.test(email)); 
// Повторяем цикл, пока введённый email НЕ проходит проверку по шаблону
// emailPattern.test(email) возвращает true, если строка подходит под шаблон
// ! — означает «не»: если проверка не прошла, продолжаем спрашивать

console.log(`Введён корректный email: ${email}`); 
// Когда пользователь ввёл правильный email, выводим его в консоль

Как работает этот код

  • Пользователь вводит email.
  • Программа проверяет его по шаблону (регулярному выражению).
  • Если email неправильный (например, нет @, точки или есть пробелы) — цикл do…while продолжает спрашивать.
  • Как только введён корректный email, программа выходит из цикла и выводит сообщение в консоль.

Когда это может быть нужно на практике

  • Ввод имени. Когда пользователь заходит в игру или на сайт, нужно обязательно запросить имя. Даже если он сначала ничего не ввёл, программа должна продолжать спрашивать, пока не получит нормальный ответ.
  • Начальные настройки. Когда вы запускаете приложение в первый раз, оно может попросить указать язык, тему оформления и так далее. Это тоже можно реализовать с помощью do…while.
  • Циклы с подтверждением. Например, пользователь получает сообщение: «Операция не выполнена. Хотите повторить попытку?» Даже если пользователь ответит «нет», первый запрос будет обязательно показан.

Цикл for: повторяем действие определённое количество раз

Цикл for отлично подходит, когда известно, сколько раз нужно выполнить действие. Он объединяет в себе сразу три части: начальное значение, условие окончания и шаг итерации, поэтому с помощью for удобно работать с числами и массивами.

for (начало; условие; шаг) {
    // Код, который будет повторяться
}

Алгоритм работы

  • Задаётся начальное значение переменной.
  • Проверяется условие — если оно истинно, выполняется тело цикла.
  • После каждой итерации переменная изменяется согласно шагу.
  • Когда условие становится ложным, цикл прекращается.

Порядок действий всегда одинаковый: сначала счётчик, потом условие, потом шаг.

Пример использования

Сначала разберём, как бы выглядел код для вывода на экран элементов списка задач с помощью цикла for.

const tasks = ['Купить продукты', 'Позвонить маме', 'Подготовить проект'];

for (let i = 0; i < tasks.length; i++) {
    console.log(`Задача №${i + 1}: ${tasks[i]}`);
}

// Вывод:
// Задача №1: Купить продукты
// Задача №2: Позвонить маме
// Задача №3: Подготовить проект

Теперь представим, что вы хотите приложить фото заметок к некоторым задачам и у вас есть список ссылок на изображения. Разберём, как цикл for может подготовить данные для вывода.

const imageUrls = ['image1.jpg', 'image2.jpg', 'image3.jpg']; // Создаём массив строк — это пути к изображениям

const gallery = []; // Создаём пустой массив gallery, куда позже добавим объекты с данными об изображениях

for (let i = 0; i < imageUrls.length; i++) { // Запускаем цикл for, который перебирает все элементы массива imageUrls
    const img = {
        src: imageUrls[i], // Путь к изображению — берём его из imageUrls[i]
        alt: `Изображение ${i + 1}` // Альтернативный текст, например "Изображение 1", "Изображение 2" и так далее
    };

    gallery.push(img); // Добавляем объект img в массив gallery
}

В результаты мы получим массив из трёх объектов, который потом удобно использовать для вывода изображений на страницу или для передачи данных на сервер.

[
  { src: 'image1.jpg', alt: 'Изображение 1' },
  { src: 'image2.jpg', alt: 'Изображение 2' },
  { src: 'image3.jpg', alt: 'Изображение 3' }
]

Когда for может быть полезен на практике

  • Рассылка уведомлений: вы хотите отправить сообщение каждому пользователю в списке, — цикл перебирает список и отправляет сообщение.
  • Загрузка фотографий: у вас есть 20 файлов, — цикл по номерам файлов загружает их по очереди на сервер.
  • Подсчёт баллов: ученики сдают 10 тестов, — цикл складывает баллы каждого теста, чтобы получить итоговый результат.

Особенности циклов for…of и for…in в JavaScript

Когда вы работаете с массивами задач или объектами с данными, часто нужно перебрать их содержимое: либо значения (например, названия задач), либо ключи (например, поля в объекте). Для этого в JavaScript есть два удобных цикла — for…of и for…in.

Цикл for…of: перебираем значения массива

Если у вас есть массив задач и вы хотите пройтись по каждой задаче, используйте for…of. Это простой способ перебрать все значения в списке.

Допустим, у нас есть список задач. Мы хотим по очереди показать каждую из них на экране. Нам не нужен номер задачи — только сами тексты.

const tasks = ['Купить продукты', 'Сделать домашку', 'Погулять с собакой'];
// Создаём массив задач — список строк, где каждая строка — отдельная задача

for (const task of tasks) {
// Начинаем цикл for...of:
// На каждой итерации переменная task будет принимать следующее значение из массива tasks

    console.log(`Задача: ${task}`);
// Выводим текущую задачу в консоль, подставляя её значение в текст
// Например: "Задача: Купить продукты"
}

Цикл выполнится три раза — по количеству элементов в массиве. На каждой итерации переменная task будет содержать следующее значение из массива.

Цикл for…in: перебираем ключи объекта

Обычный for не работает с объектами — у объекта нет индексов, только ключи. Если у вас есть объект, который описывает одну задачу, и вы хотите перебрать все её поля — используйте for…in.

const task = {
    title: 'Позвонить другу',
    completed: false,
    priority: 'высокий'
}; 
// Создаём объект task — это набор пар «ключ — значение»
// title — название задачи
// completed — выполнена ли задача (true или false)
// priority — приоритет задачи
for (const key in task) {
// Начинаем цикл for...in
// На каждой итерации переменная key будет принимать следующее имя свойства из объекта task
// Сначала key = 'title', потом 'completed', потом 'priority'
    console.log(`${key}: ${task[key]}`);
// Выводим имя свойства и его значение через двоеточие
// task[key] — доступ к значению по имени свойства
// Например: "title: Позвонить другу"
}

Здесь key — это название свойства (например, priority), а user[key] — его значение (например, "высокий").

Разница между for…in и for…of

В JavaScript массив — это на самом деле тоже объект. А это значит, что ему можно добавить не только числовые элементы, но и обычные свойства, как у любого объекта. Посмотрим на пример, где массиву вручную добавляется дополнительное свойство. Мы сравним, как себя ведут циклы for…in и for…of.

const tasks = ['Купить продукты', 'Погулять с собакой']; arr.customProp = "я лишний"; // добавление свойства объекту for (const i in arr) { console.log(`for...in: ${i} -> ${arr[i]}`); } for (const val of arr) { console.log(`for...of: ${val}`); }

Что здесь происходит

Массив arr имеет дополнительное свойство — customProp. Это не элемент массива, а как будто ярлык сбоку.

Цикл for…in перебирает все перечисляемые свойства объекта, включая:

  • индексы массива (0, 1, 2),
  • любые добавленные свойства, такие как customProp.

Цикл for…of перебирает только значения массива — без «лишнего», без ключей, без свойств.

Совет: если работаете с массивами и не хотите наткнуться на случайные свойства, используйте for…of.

Прерывание и перезапуск цикла

Иногда в процессе выполнения цикла нужно досрочно остановить его или, наоборот, пропустить текущую итерацию и перейти к следующей. В JavaScript для этого используется два ключевых слова: break и continue.

Оператор break: прерывание выполнения

Если внутри цикла срабатывает break, выполнение цикла немедленно останавливается и программа продолжает работать дальше — уже после цикла.

Предположим, у нас есть массив задач и мы хотим найти первую задачу, где надо кому-то позвонить.

const tasks = ['Позвонить в авиакомпанию', 'Сделать домашнее задание', 'Позвонить другу'];

for (let i = 0; i < tasks.length; i++) {
  if (tasks[i].toLowerCase().includes('позвонить')) { // Переводим всё в нижний регистр для проверки и ищем слово «позвонить»
    console.log(`Нужно позвонить: ${tasks[i]}`);
    break; //Выходим из цикла после вывода 1-й задачи 
  }
}

В этом примере цикл перебирает массив задач и останавливается при нахождении первой выполненной задачи, что ускоряет процесс.

Оператор continue: пропуск текущей итерации

Если внутри цикла срабатывает continue, текущая итерация прерывается, но сам цикл продолжается — сразу переходит к следующему шагу.

Допустим, мы хотим вывести только задачи, связанные с покупками.

const tasks = ['Купить билеты в кино', 'Устранить ошибки в проекте', 'Купить хлеба'];

for (let i = 0; i < tasks.length; i++) {
  if (!tasks[i].toLowerCase().includes('купить')) {
    continue; // Пропускаем задачи, не связанные с покупками
  }

  console.log(`Задача на покупку: ${tasks[i]}`);
}

В этом случае цикл пропускает все задачи, которые уже выполнены, и выводит только те, что ещё предстоит выполнить.

Типичные ошибки при работе с циклами в JavaScript: как их избежать

Разберём самые частые проблемы и объясним, как их не допустить.

Ошибка: неверные условия в цикле for

// Предполагаем, что хотим выполнить пять итераций
for (let i = 0; i >= 0; i++) {
    console.log("Добавить задачу");
}
// Цикл повторяется бесконечно

Почему так происходит: i всегда больше или равно 0 и с каждой итерацией увеличивается. Условия повторения цикла всегда верное.

Правильный вариант: проверьте, действительно ли условие даёт выход.

for (let i = 0; i < 5; i++) {
    console.log("Добавить задачу");
}

Ошибка: отсутствие переменной-счётчика в цикле while

let i = 0;

while (i < 5) {
    console.log('Добавлена новая задача');
    // Забыли i++
}
// Цикл повторяется бесконечно

Почему так происходит: переменная i никогда не изменяется, условие i < 5 всегда истинно, цикл продолжается бесконечно.

Правильный вариант: убедитесь, что в теле цикла переменная-счётчик корректно изменяется, чтобы условие цикла могло стать ложным.

let i = 0;

while (i < 5) {
    console.log('Добавлена новая задача');
    i++;
}

Запомните: если условие верно всегда, то цикл никогда не заканчивается и браузер зависает.

Ошибка: вы перебираете массив задач, но условие в цикле допускает индекс, которого уже нет

const tasks = ['Сходить в кино', 'Убраться', 'Купить подарок маме'];

for (const task of tasks) {
    console.log(task);
}

// Вывод на экран:
// Сходить в кино
// Убраться
// Купить подарок маме
// undefined

Почему так происходит: Массив tasks имеет три элемента с индексами 0, 1 и 2. Условие i <= tasks.length приводит к попытке доступа к tasks[3], которого не существует.

Правильный вариант: используйте условие < вместо <=, чтобы избежать выхода за пределы массива.

for (let task of tasks) {
    console.log(task);
}

Ошибка: удаление элементов из массива внутри цикла может привести к пропуску элементов

const tasks = ['Купить продукты', 'Уборка: помыть посуду', 'Уборка: пропылесосить'];

// Удаляем всё со словом «уборка»
for (const task of tasks) {
    if (task.includes('Уборка')) {
        tasks.splice(i, 1); // Начиная с позиции i, удалить 1 элемент в массиве 
    }
}

console.log(tasks);

//Вывод
//['Купить продукты', 'Уборка: пропылесосить']

Почему так происходит: Когда удаляешь tasks[i], все элементы сдвигаются влево. 'Уборка: помыть посуду' удаляется, но i становится 1, а 'Уборка: пропылесосить' сдвигается на место под индексом 1 — и остаётся незамеченной.

Правильный вариант: идти с конца. Когда идёшь от последнего элемента к первому, сдвиги уже не мешают.

for (let i = tasks.length - 1; i >= 0; i--) {
    if (tasks[i].includes('Уборка')) {
        tasks.splice(i, 1);
    }
}

Ошибка: общий счётчик задач, расположенный после break и continue.

const tasks = ['Работа над проектом', 'Погулять с собакой', 'Работа в Notion'];

let total = 0;

for (const task of tasks) {
    if (task.includes('Работа')) {
        continue; // Пропускаем задачи со словом «работа»
    }

    console.log(`Задача: ${task}`);
    total++; // Считаем только задачи, которые не были пропущены
}

console.log(`Всего задач: ${total}`);

Почему так происходит: из-за того, что continue стоит до total++, пропущенные задачи не попадают в общий счётчик.

Правильный вариант:

let total = 0;

for (const task of tasks) {
    total++; // Учитываем задачу независимо от фильтра

    if (task.includes('Работа')) {
        continue; // Скрываем в интерфейсе, но не теряем в статистике
    }

    console.log(`Задача: ${task}`);
}

console.log(`Всего задач: ${total}`);

Советы и лайфхаки для работы с циклами в JavaScript

Сохраняйте длину массива в переменную

Когда вы перебираете массив с помощью цикла for, выражение array.length каждый раз заново рассчитывает длину массива. Это не всегда критично, но, если массив большой или цикл запускается много раз, лишние вычисления могут замедлить выполнение.

Пример менее эффективного кода:

for (let i = 0; i < array.length; i++) {
  // ...
}

Здесь array.length вызывается на каждой итерации.

Более эффективный вариант:

const len = array.length;
for (let i = 0; i < len; i++) {
  // ...
}

Здесь длина массива сохраняется в переменную len один раз — и используется в цикле без лишних обращений к свойству .length.

Будьте аккуратны с вложенными циклами

  • Используйте понятные имена переменных, например taskIndex вместо i, это делает код понятнее.
  • Чем больше уровней вложенности, тем сложнее читать и понимать код.
  • Если у вас три и более уровней for, скорее всего, логику можно упростить. Разбейте задачу на шаги или преобразуйте данные заранее.
  • Если в каждом уровне вложенности используется один и тот же код, лучше вынести его за пределы цикла или оформить как отдельную функцию.
  • Во вложенных циклах break и continue работают только на ближайший цикл. Выйти сразу из двух не получится.

Выводите результат после завершения цикла

  • Если вы хотите получить итог — например, общее количество задач или результат вычислений, — не размещайте console.log() внутри цикла, если он не должен повторяться.
  • Если разместить console.log() вне цикла, он выполнится только один раз — после завершения цикла — и выведет итоговое значение.

Практика: тренируемся в использовании циклов в JavaScript

Упражнение 1: вывести сумму чётных чисел

Задание: переберите массив чисел и получите сумму всех чётных значений.

Массив:

let numbers = [1, 4, 7, 10, 12];

Решение

let sum = 0;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) { // Проверяем на чётность
    sum += numbers[i]; // Добавляем в сумму
  }
}

console.log(sum); // 26

Упражнение 2: подсчёт выполненных задач

Переберите массив задач и выведите количество задач, помеченных как выполненные.

Массив:

let tasks = [
  { title: 'Купить продукты', completed: true },
  { title: 'Сделать домашку', completed: false },
  { title: 'Позвонить маме', completed: true }
];

Совет: для проверки определённого свойства объекта используйте выражение tasks[i].completed.

Решение

let done = 0;

for (let i = 0; i < tasks.length; i++) {
    if (tasks[i].completed === true) { // Если задача отмечена как выполненная
    done++; // увеличиваем счётчик на 1
  }
}

console.log(done); // 2

Упражнение 3: удаление пустых строк

Пройдитесь по массиву строк и создайте новый массив без пустых строк или строк, состоящих только из пробелов.

Массив:

let input = ['задача 1', '', '  ', 'задача 2'];

Совет: используйте .trim() — метод строк в JavaScript, который удаляет пробелы и и другие «пустые» символы в начале и в конце строки.

Решение

let cleaned = [];

for (let i = 0; i < input.length; i++) {
  if (input[i].trim() !== '') {
    cleaned.push(input[i]);
  }
}

console.log(cleaned); // ['задача 1', 'задача 2']



Бесплатный курс

Веб-разработка с нуля

Создайте 3 приложения и сделайте первый шаг к карьере веб-разработчика. Для обучения не нужны опыт и знания в IT.

Учитесь бесплатно →

Бесплатный курс: «Веб-разработка с нуля» Начать учиться
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована