Как правильно перебрать массив в JavaScript: forEach, for, for...of и другие способы
const users = ['Анна', 'Иван', 'Мария', 'Петр'];
Мне нужно вывести каждое имя в консоль. Я пробовал использовать обычный цикл for, но у меня постоянно путаница с индексами и длиной массива. Например, я пишу:
for (let i = 0; i <= users.length; i++) {
console.log(users[i]);
}
И в конце получаю undefined. Почему так происходит? Я слышал, что есть метод forEach, но не понимаю, как он работает и чем отличается от обычного for. Ещё видел какие-то for...of и for...in, но совсем запутался.
Подскажите, пожалуйста, какой способ лучше использовать для перебора массива в современных проектах? Мне нужно не просто вывести элементы, но иногда и изменить их, или создать новый массив на основе существующего. Буду благодарен за подробное объяснение с примерами для новичков.
<<Основные способы перебора массива в JavaScript
Давайте разберём все популярные способы итерации по массиву, начиная с вашей ошибки.
1. Классический цикл for
Ваша ошибка — использование <= вместо <. Индексы массива начинаются с 0, поэтому последний элемент имеет индекс length - 1. Правильно:
const users = ['Анна', 'Иван', 'Мария', 'Петр'];
for (let i = 0; i < users.length; i++) {
console.log(users[i]); // Анна, Иван, Мария, Петр
}
Этот способ даёт полный контроль: вы можете менять элементы по индексу, прерывать цикл через break, использовать continue.
2. Метод forEach() — современный стандарт
Самый читаемый способ для простого перебора. Вызывается прямо на массиве и принимает функцию-колбэк:
users.forEach(function(user, index) {
console.log(`${index}: ${user}`);
});
// Вывод: 0: Анна, 1: Иван, 2: Мария, 3: Петр
Стрелочная функция делает код ещё короче:
users.forEach((user, index) => console.log(`${index}: ${user}`));
Важно: forEach не возвращает новый массив, его нельзя прервать через break, и он не работает с await внутри колбэка (в таких случаях используйте for...of).
3. Цикл for...of — для работы с элементами
Появился в ES6, идеален, когда нужны только значения, а не индексы:
for (const user of users) {
console.log(user); // Анна, Иван, Мария, Петр
}
Можно использовать break и continue, а также await внутри цикла. Если нужен индекс, используйте entries():
for (const [index, user] of users.entries()) {
console.log(`${index}: ${user}`);
}
4. for...in — НЕ используйте для массивов!
Этот цикл предназначен для объектов. Он перебирает не только индексы, но и все перечисляемые свойства, включая унаследованные. Результат непредсказуем:
for (const key in users) {
console.log(key); // "0", "1", "2", "3" (строки, а не числа!)
}
Когда что использовать?
- Нужен индекс и/или изменение элементов — классический
forилиforEachс индексом. - Просто перебрать значения —
for...ofилиforEach. - Создать новый массив —
map()(см. ниже). - Асинхронные операции внутри цикла —
for...ofсawait.
Продвинутые методы (функциональный подход)
Современный JavaScript предлагает методы, которые возвращают новые массивы:
// map — создаёт новый массив, преобразуя каждый элемент
const upperUsers = users.map(user => user.toUpperCase());
// ['АННА', 'ИВАН', 'МАРИЯ', 'ПЕТР']
// filter — фильтрует элементы по условию
const longNames = users.filter(user => user.length > 3);
// ['Анна', 'Мария', 'Петр']
// reduce — свёртка массива в одно значение
const allNames = users.reduce((acc, user) => acc + ' ' + user, 'Пользователи:');
// 'Пользователи: Анна Иван Мария Петр'
Эти методы не изменяют исходный массив, что соответствует принципам иммутабельности и упрощает отладку.
<<Альтернативный подход: методы map(), filter() и reduce()
Если ваша цель — не просто перебрать массив, а преобразовать его или получить новую структуру данных, функциональные методы часто удобнее циклов.
Рассмотрим реальную задачу: у нас есть массив объектов с пользователями, и нужно получить массив имён только совершеннолетних пользователей:
const users = [
{ name: 'Анна', age: 17 },
{ name: 'Иван', age: 25 },
{ name: 'Мария', age: 19 },
{ name: 'Петр', age: 16 }
];
// Решение через цепочку методов
const adultNames = users
.filter(user => user.age >= 18) // оставляем только взрослых
.map(user => user.name); // забираем только имена
console.log(adultNames); // ['Иван', 'Мария']
Такой код читается как последовательность шагов: «отфильтруй, затем преобразуй». Он не мутирует исходный массив, что предотвращает побочные эффекты.
Когда это не подходит:
- Если нужно прервать цикл досрочно (нет аналога
break). - Если внутри колбэка есть асинхронные операции (лучше
for...ofсawait). - Если производительность критична (для гигантских массивов классический
forбыстрее).
В остальных случаях функциональный подход делает код чище и предсказуемее. Рекомендую освоить map, filter и reduce — это основа стиля современного JavaScript.