Итерация по массиву в JavaScript: 5 фатальных ошибок и как их избежать

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как перебирать массив в JavaScript: Топ ошибок и как их избежать

Вы когда-нибудь писали код, который должен был просто пройтись по списку дел или товаров в корзине, а вместо этого выдавал undefined, бесконечный цикл или, что еще хуже, тихо портил данные? Знакомая боль. Вопрос "How to loop through the items of an array in JavaScript?" — один из самых популярных на Stack Overflow. Кажется, что может быть проще? Но дьявол, как всегда, кроется в деталях.

Сегодня мы не просто разберем, как перебирать массив в JavaScript. Мы заглянем под капот самых частых граблей, на которые наступают новички (и не только). Вы узнаете, почему for...in может вас подставить, чем forEach отличается от map, и как не словить бесконечный цикл в for.

Готовы? Погнали чинить баги и писать красивый код.

Ошибка №1: Использование for...in для массивов

Это, пожалуй, самый коварный новичковый трепет. Разработчик видит слово for и слово in и думает: "О, это же для перебора всего подряд!". Технически это правда. Но для массивов это катастрофа.

Цикл for...in предназначен для перебора свойств объекта, а не элементов массива. Да, массив в JS — это тоже объект, но его индексы — это всего лишь строковые ключи ("0", "1", "2").

Вот в чем подвох:

  • Порядок не гарантирован. Хотя обычно браузеры соблюдают порядок, полагаться на это нельзя.
  • Он перебирает всё прототипное наследование. Если вы или какая-то библиотека добавили метод в Array.prototype (например, Array.prototype.myCustomMethod = function() {}), for...in подхватит и его.

Пример кода (как делать НЕ надо):

const arr = [10, 20, 30];
Array.prototype.customMethod = () => {};

for (let index in arr) {
  console.log(arr[index]); // Выведет: 10, 20, 30, ƒ () => {}
}

Видите? В конце вылезла наша кастомная функция. Код сломался.

Как правильно:

Используйте for...of (для значений) или классический for (для индексов). for...of перебирает только значения и игнорирует прототип.

// Правильно и безопасно
for (let value of arr) {
  console.log(value); // 10, 20, 30
}

Ошибка №2: Забыть про колбэк в forEach

arr.forEach(callback) — это элегантный способ перебора массива в JavaScript. Но многие путают его с map или filter. Главная ошибка — думать, что forEach что-то возвращает. Он возвращает undefined.

Вторая распространенная ошибка — забывать про второй и третий аргументы колбэка (индекс и сам массив). Иногда это критично.

Пример ошибки:

const numbers = [1, 2, 3];
const doubled = numbers.forEach(num => num * 2);
console.log(doubled); // undefined! Ошибка.

Как правильно:

Если вам нужно создать новый массив на основе старого — используйте map(). Если нужно только выполнить действие (например, вывести в консоль или отправить данные) — используйте forEach().

// Для создания нового массива
const doubled = numbers.map(num => num * 2); // [2, 4, 6]

// Для побочных эффектов
numbers.forEach((num, index) => {
  console.log(`Элемент ${index}: ${num}`);
});

Ошибка №3: Бесконечный цикл в for

Классика жанра. Вы пишете for (let i = 0; i < arr.length; i++), но забываете про инкремент i++ или, что еще хуже, меняете массив внутри цикла.

Допустим, вы фильтруете массив на лету, удаляя элементы с помощью splice(). Если вы не скорректируете индекс, вы пропустите элементы.

Пример кода (как делать НЕ надо):

let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
  if (arr[i] % 2 === 0) {
    arr.splice(i, 1); // Удаляем элемент
  }
}
console.log(arr); // [1, 3, 5]? Нет. Будет [1, 3, 4, 5] — элемент 4 пропущен!

Почему? Потому что после удаления элемента с индексом 1 (число 2), элемент "3" смещается на индекс 1, а цикл уже переходит к индексу 2. Мы пропустили проверку.

Как правильно:

Самый надежный способ — идти по массиву с конца.

let arr = [1, 2, 3, 4, 5];
for (let i = arr.length - 1; i >= 0; i--) {
  if (arr[i] % 2 === 0) {
    arr.splice(i, 1);
  }
}
console.log(arr); // [1, 3, 5] — теперь правильно!

Или используйте filter(), который создает новый массив и не мутирует исходный (если вы этого не хотите).

Ошибка №4: Путаница между map() и forEach()

Эта ошибка тесно связана с пунктом 2. Многие новички, изучая методы массивов в JavaScript, не понимают разницы между итерацией и трансформацией.

  • forEach() — это "сделай что-то с каждым элементом". Результат работы колбэка игнорируется.
  • map() — это "создай новый массив, применив функцию к каждому элементу". Результат каждого вызова колбэка собирается в новый массив.

Если вы пишете arr.map(x => console.log(x)) — вы делаете это неправильно. Вы создаете новый массив из undefined (потому что console.log ничего не возвращает) и тратите память.

Как правильно:

Всегда задавайте себе вопрос: "Мне нужен новый массив на выходе?". Если да — map, filter, reduce. Если нет — forEach.

Ошибка №5: Использование for, когда есть более читаемые методы

Блоги

Рекомендаций по книгам