</> Praktum

Главная / JavaScript / Метод forEach

Справочник · JavaScript

Метод forEach(): перебор массива

Редакция PraktumОбновлено 5 мин чтенияУровень: новичок

Метод forEach(callback) вызывает функцию для каждого элемента массива по порядку. Функция получает элемент, его индекс и сам массив. forEach ничего не возвращает (undefined) и не умеет останавливаться посередине: break и return не прерывают перебор. Если нужно новое значение — используй map, если нужна остановка — for...of.

Коротко
  • arr.forEach((item, i) => {...})
  • Возвращает undefined — результат не собирает.
  • break не работает, return лишь пропускает элемент.
  • С await внутри не ждёт — используй for...of.
  • Есть у NodeList из querySelectorAll.

Минимальный пример

const tasks = ['Купить хлеб', 'Позвонить маме', 'Сделать ДЗ'];
const list = document.querySelector('#tasks');

tasks.forEach((task, index) => {
  const li = document.createElement('li');
  li.textContent = `${index + 1}. ${task}`;
  list.append(li);
});

Для каждой задачи создаётся пункт списка с номером. forEach подходит, когда нужно сделать что-то с каждым элементом — вывести, отправить, изменить DOM — без сбора нового массива.

Аргументы callback

Что получает функция
АргументЗначение
itemтекущий элемент
indexего индекс
arrayсам массив

Чаще всего нужны первые два. Пустые ячейки разреженного массива forEach пропускает.

Почему нельзя прервать

[1, 2, 3, 4].forEach((n) => {
  if (n === 2) return;   // пропустит только 2, перебор продолжится
  console.log(n);        // 1, 3, 4
});

for (const n of [1, 2, 3, 4]) {
  if (n === 3) break;    // остановится
  console.log(n);        // 1, 2
}

[1, 2, 3, 4].some((n) => n === 3);   // true — остановится на 3

return внутри callback выходит только из текущего вызова функции — это аналог continue. break внутри функции — синтаксическая ошибка. Если нужно остановиться, используй for...of, или find/some/every, которые сами прекращают перебор, когда ответ найден.

forEach или map

// плохо: forEach + push
const names = [];
users.forEach((u) => names.push(u.name));

// хорошо: map
const names2 = users.map((u) => u.name);

Если цель — новый массив из преобразованных элементов, map короче и понятнее. forEach — для побочных эффектов: вывода, изменения DOM, отправки данных. Подробнее — метод map.

forEach и async/await

// не ждёт: forEach запустит все запросы и сразу завершится
ids.forEach(async (id) => {
  await saveItem(id);
});
console.log('готово');   // напечатается раньше, чем сохранится

// по очереди
for (const id of ids) {
  await saveItem(id);
}

// параллельно, но дождаться всех
await Promise.all(ids.map((id) => saveItem(id)));

forEach не знает про промисы и не ждёт асинхронные функции. Для последовательного выполнения — for...of с await, для параллельного — Promise.all с map.

Перебор элементов страницы

document.querySelectorAll('.faq-item').forEach((item) => {
  item.querySelector('button').addEventListener('click', () => {
    item.classList.toggle('is-open');
  });
});

// HTMLCollection forEach не имеет
[...document.getElementsByClassName('card')].forEach((card) => { /* … */ });

У NodeList из querySelectorAll есть forEach. У HTMLCollection из getElementsByClassName — нет, её сначала превращают в массив.

Изменение массива во время перебора

const arr = [2, 4, 6, 7];
arr.forEach((n, i) => {
  if (n % 2 === 0) arr.splice(i, 1);   // индексы сдвигаются
});
arr;  // [4, 7] — четвёрка пропущена

const odd = [2, 4, 6, 7].filter((n) => n % 2 !== 0);   // [7] — правильно

Удаление элементов внутри forEach сдвигает индексы, и часть элементов пропускается. Для удаления используй filter, который создаёт новый массив.

forEach или for...of

for...of

Можно break, continue и await. Работает с любыми перебираемыми объектами.

forEach

Короткая запись с индексом. Нельзя прервать, не ждёт await.

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

  • Пытаются выйти из forEach через break или return.
  • Используют forEach + push вместо map.
  • Пишут await внутри forEach и ждут последовательного выполнения.
  • Удаляют элементы из массива во время перебора.
  • Ждут, что forEach вернёт новый массив.

Доступность

Создавая элементы в цикле, добавляй их в DOM разом через фрагмент или append с несколькими аргументами — меньше перерисовок. Для динамически добавленных списков сообщай о результате через aria-live, например «Найдено 12 товаров».

Поддержка браузерами

forEach поддерживается всеми браузерами. forEach у NodeList — во всех актуальных браузерах.

Практика

Есть массив товаров { name, price }. Выведи их в список #cart пунктами «Название — цена ₽» и посчитай общую сумму в #total. Используй forEach для вывода и reduce для суммы.

Показать решение
const cart = [
  { name: 'Кроссовки', price: 5990 },
  { name: 'Носки', price: 390 },
];
const list = document.querySelector('#cart');

cart.forEach(({ name, price }) => {
  const li = document.createElement('li');
  li.textContent = `${name} — ${price} ₽`;
  list.append(li);
});

const total = cart.reduce((sum, item) => sum + item.price, 0);
document.querySelector('#total').textContent = `${total} ₽`;

Открыть песочницу

Частые вопросы

Как перебрать массив в JavaScript?

arr.forEach((item, i) => {...}) или for (const item of arr).

Как прервать forEach?

Никак. Используй for...of с break или методы some, every, find.

Что возвращает forEach?

undefined. Для нового массива используй map.

Работает ли await внутри forEach?

Нет, forEach не ждёт промисы. Используй for...of или Promise.all.

Чем forEach отличается от map?

map возвращает новый массив, forEach только выполняет действие для каждого элемента.

Источники

Ещё в разделе JavaScript