Перебор массива js с помощью циклов и методов
Перебор массива js выбирают по результату: пройти элементы, создать новый массив, найти значение или остановиться при первом совпадении. В этой статье разобраны циклы, методы массивов, перебор объекта js и асинхронный код. Каждый пример можно запустить в консоли браузера или в Node.js.
- Как перебрать массив в JavaScript: какой способ выбрать
- Как перебрать массив по индексам через for
- Как перебрать значения массива через for...of
- Как работает forEach в JavaScript
- Как преобразовать массив через map, filter и reduce
- Как найти и проверить элементы через find, findIndex, some и every
- Как прервать перебор массива досрочно
- Перебор объекта js через Object.keys, Object.values и Object.entries
- Почему массив не перебирают через for...in
- Перебор массива с async/await
- Производительность методов перебора
- Ошибки при переборе массива
- Как выбрать способ перебора массива под задачу
Как перебрать массив в JavaScript: какой способ выбрать
Сначала определите результат операции. Циклы подходят для произвольных действий, методы массива сразу показывают намерение кода.
| Задача | Метод | Возвращает | Можно прервать | Меняет исходный массив |
|---|---|---|---|---|
| Пройти элементы и управлять индексом | for | – | Да, через break | Только действиями внутри цикла |
| Пройти значения | for...of | – | Да, через break | Только действиями внутри цикла |
| Выполнить действие для каждого элемента | forEach | undefined | Нет штатного раннего выхода | Сам метод нет; колбэк может |
| Преобразовать каждый элемент | map | Новый массив | Нет штатного раннего выхода | Сам метод нет; колбэк может |
| Оставить подходящие элементы | filter | Новый массив | Нет штатного раннего выхода | Сам метод нет; колбэк может |
| Свернуть элементы в одно значение | reduce | Значение аккумулятора | Нет штатного раннего выхода | Сам метод нет; колбэк может |
| Найти элемент | find | Элемент или undefined | Да, при совпадении | Сам метод нет; колбэк может |
| Найти индекс | findIndex | Индекс или -1 | Да, при совпадении | Сам метод нет; колбэк может |
| Проверить хотя бы один элемент | some | Логическое значение | Да, при истинном условии | Сам метод нет; колбэк может |
| Проверить все элементы | every | Логическое значение | Да, при ложном условии | Сам метод нет; колбэк может |
Для простого обхода берите for...of. Для преобразования используйте map, для отбора – filter, для одного ответа – find или reduce.
Ни один из перечисленных методов сам не мутирует исходный массив. Однако колбэк может заменить элемент, удалить его или изменить вложенный объект.
Как перебрать массив по индексам через for
Цикл for дает индекс и полный контроль над остановкой. Такой цикл по массиву в JS удобен для обратного прохода и изменения элементов.
const numbers = [1, 2, 3, 4, 5];
for (let index = 0; index < numbers.length; index += 1) {
if (numbers[index] === 4) {
break;
}
console.log(numbers[index]);
}
// Результат: 1, 2, 3 (отдельными вызовами)В круглых скобках стоят инициализация счетчика, условие продолжения и изменение счетчика.
Оператор break завершает цикл, а continue пропускает текущую итерацию. В приведенном примере длина проверяется перед каждым проходом тела цикла.
const values = [10, 20, 30, 40];
for (let index = values.length - 1; index >= 0; index -= 1) {
console.log(values[index]);
}
// Результат: 40, 30, 20, 10 (отдельными вызовами)Сохраняйте длину отдельно, если логика требует зафиксировать исходную границу обхода. Само по себе такое сохранение не гарантирует ускорения.
Как перебрать значения массива через for...of
for...of перебирает значения и скрывает техническую работу с индексом. Для большинства задач перебор массива в JavaScript с этим циклом читается проще.
const colors = ['red', 'green', 'blue'];
for (const color of colors) {
console.log(color);
}
// Результат: red, green, blue (отдельными вызовами)Индекс можно получить через entries(). Цикл сохраняет break и continue, поэтому подходит для раннего выхода.
const users = ['Анна', 'Борис', 'Вера'];
for (const [index, user] of users.entries()) {
if (index === 1) {
continue;
}
console.log(`${index}: ${user}`);
}
// Результат: 0: Анна, затем 2: ВераВыбирайте for, когда нужен сложный расчет индекса. В остальных случаях цикл по массиву через for...of обычно читается понятнее.
Как работает forEach в JavaScript
Метод forEach вызывает колбэк для каждого существующего элемента массива. Колбэк получает значение, индекс и исходный массив.
const numbers = [2, 4, 6];
numbers.forEach((value, index, array) => {
console.log(value, index, array === numbers);
});
// Результат: 2 0 true, затем 4 1 true, затем 6 2 trueМетод forEach выполняет действие для каждого существующего элемента массива. Сам forEach возвращает undefined, независимо от результата колбэка.
const names = ['Лена', 'Олег'];
const result = names.forEach((name) => name.toUpperCase());
console.log(result);
// Результат: undefinedreturn завершает только текущий колбэк. Остановить весь forEach оператором break нельзя. Для нового массива берите map, а для раннего выхода – цикл или find.
Подробное описание метода есть в справке forEach на MDN.
Как преобразовать массив через map, filter и reduce
Три метода возвращают разные результаты: map преобразует, filter отбирает, reduce сворачивает. Сами методы не изменяют исходный массив, но действия колбэков могут его изменить.
map создает новый массив
const prices = [100, 200, 300];
const withTax = prices.map((price) => price * 1.2);
console.log(withTax);
// Результат: [120, 240, 360]Колбэк должен вернуть значение. Если убрать return у стрелочной функции с фигурными скобками, обработанные позиции заполнятся undefined.
filter оставляет подходящие элементы
const numbers = [1, 2, 3, 4, 5, 6];
const even = numbers.filter((number) => number % 2 === 0);
console.log(even);
// Результат: [2, 4, 6]Методы можно объединять. Сначала фильтр оставит активные записи, затем map возьмет из них названия.
const users = [
{ name: 'Анна', active: true },
{ name: 'Борис', active: false },
{ name: 'Вера', active: true }
];
const activeNames = users.filter((user) => user.active).map((user) => user.name);
console.log(activeNames);
// Результат: ['Анна', 'Вера']Метод filter в JavaScript отбирает элементы массива по условию. Колбэк сохраняет элемент, если возвращает истинное в логическом контексте значение. В примере он возвращает true или false.
Не меняйте элементы внутри фильтра: оставьте колбэку только проверку условия.
reduce получает одно значение
const numbers = [3, 5, 7];
const sum = numbers.reduce((total, number) => total + number, 0);
console.log(sum);
// Результат: 15Начальное значение 0 задает аккумулятор для первого вызова колбэка. На пустом массиве этот расчет тоже вернет 0. Без начального значения reduce на пустом массиве выбросит TypeError.
Для группировки аккумулятором может быть объект.
const words = ['a', 'bb', 'c'];
const grouped = words.reduce((result, word) => {
const length = word.length;
result[length] ??= [];
result[length].push(word);
return result;
}, {});
console.log(grouped);
// Результат: {1: ['a', 'c'], 2: ['bb']}В этом примере колбэк изменяет отдельный объект-аккумулятор. Исходный массив words остается прежним.
Как найти и проверить элементы через find, findIndex, some и every
Эти методы сами останавливаются, когда ответ уже найден. Они не создают новый массив и сами не изменяют исходный.
const users = ['Анна', 'Борис', 'Вера'];
const user = users.find((name) => name.startsWith('В'));
const index = users.findIndex((name) => name.startsWith('В'));
console.log(user, index);
// Результат: Вера 2find возвращает элемент или undefined. findIndex возвращает индекс или -1. Проверяйте найденный индекс явным сравнением с -1.
const names = ['Анна', 'Борис'];
const index = names.findIndex((name) => name === 'Анна');
console.log(index, index !== -1);
// Результат: 0 trueУсловие if (index) даст неверную проверку наличия элемента: индекс 0 ложный, а -1 истинный.
const scores = [42, 67, 81];
const hasHighScore = scores.some((score) => score >= 80);
const allPassed = scores.every((score) => score >= 40);
console.log(hasHighScore, allPassed);
// Результат: true truesome ищет хотя бы одно совпадение, а every требует совпадения для всех посещаемых элементов. На пустом массиве some возвращает false, а every – true.
Методы findLast и findLastIndex выполняют поиск с конца массива.
Для справки по сигнатурам используйте страницы find, some и every на MDN.
Как прервать перебор массива досрочно
Оператор break завершает циклы for и for...of. Выйти из метода массива через break внутри его колбэка нельзя.
const numbers = [2, 4, 7, 8];
let firstOdd;
for (const number of numbers) {
if (number % 2 !== 0) {
firstOdd = number;
break;
}
}
console.log(firstOdd);
// Результат: 7Для проверки условия замените ручной цикл на some или every. Если нужен сам найденный элемент, используйте find.
const numbers = [2, 4, 7, 8];
const hasOdd = numbers.some((number) => number % 2 !== 0);
console.log(hasOdd);
// Результат: trueНе используйте исключение для обычного выхода из forEach. Исключение прерывает выполнение, но требует обработки ошибки и усложняет управление кодом.
Перебор объекта js через Object.keys, Object.values и Object.entries
Способ перебора объекта в JavaScript зависит от нужных данных: ключей, значений или пар. Методы Object.keys, Object.values и Object.entries ограничивают обход его собственными перечисляемыми строковыми свойствами.
Object.keys и Object.values
const user = { name: 'Ирина', age: 28 };
for (const key of Object.keys(user)) {
console.log(key, user[key]);
}
console.log(Object.values(user));
// Результат: name Ирина, age 28, затем ['Ирина', 28]Object.keys возвращает ключи, а Object.values – соответствующие значения. Эти методы не меняют объект и не включают свойства с ключами-символами.
Object.entries и деструктуризация
const settings = { theme: 'dark', language: 'ru' };
for (const [key, value] of Object.entries(settings)) {
console.log(`${key}=${value}`);
}
// Результат: theme=dark, language=ru (отдельными вызовами)Конструкция позволяет перебрать объект парами ключ–значение. Деструктуризация записывает каждую пару в переменные key и value.
У обычного объекта эти методы сначала обрабатывают ключи-индексы массива по возрастанию. Остальные перечисляемые строковые ключи следуют в порядке создания свойств. Строки '01' и '-1' не относятся к ключам-индексам массива.
const labels = { '01': 'с нулем', 10: 'десять', 2: 'два', name: 'имя' };
console.log(Object.keys(labels));
// Результат: ['2', '10', '01', 'name']for...in и наследуемые свойства
const user = Object.create({ role: 'reader' });
user.name = 'Ирина';
for (const key in user) {
if (Object.hasOwn(user, key)) {
console.log(key, user[key]);
}
}
// Результат: name Иринаfor...in перечисляет строковые ключи, включая унаследованные перечисляемые свойства. Проверка Object.hasOwn оставляет только свойства самого объекта.
Для обычных объектов без изменений во время обхода сначала идут собственные свойства, затем свойства прототипов. На каждом уровне ключи-индексы идут по возрастанию, остальные строки – по порядку создания. Повторяющиеся имена свойств цикл повторно не выдает.
Подробности перечисления свойств описаны в справке for...in на MDN.
Почему массив не перебирают через for...in
Массив хранит элементы по числовым индексам, но for...in возвращает ключи строками. В обход могут попасть дополнительные свойства и свойства прототипа.
const numbers = [10, 20];
numbers.extra = 'служебное';
for (const key in numbers) {
console.log(key, typeof key);
}
// Результат: 0 string, 1 string, extra stringИндексные ключи перечисляются по возрастанию, но цикл обходит свойства, включая дополнительные. Пустые позиции массива он пропускает. Поэтому for...in не заменяет последовательный обход всех позиций.
Для массива берите for, for...of или метод массива.
Перебор массива с async/await
forEach не ожидает промис, который возвращает асинхронный колбэк. Поэтому внешний код продолжит работу до завершения асинхронных операций.
const ids = [1, 2, 3];
const load = async (id) => id * 10;
const values = [];
ids.forEach(async (id) => {
values.push(await load(id));
});
console.log(values.length);
// Результат сразу после forEach: 0Даже await ids.forEach(...) не дождется всех колбэков: метод возвращает undefined.
Последовательный перебор выполняйте через for...of. Следующая итерация начнется после завершения текущего промиса.
const run = async () => {
const ids = [1, 2, 3];
const load = async (id) => id * 10;
const values = [];
for (const id of ids) {
values.push(await load(id));
}
console.log(values);
};
run().catch(console.error);
// Результат: [10, 20, 30]Независимые асинхронные операции запускайте совместно через map и Promise.all.
const run = async () => {
const ids = [1, 2, 3];
const load = async (id) => id * 10;
const values = await Promise.all(ids.map((id) => load(id)));
console.log(values);
};
run().catch(console.error);
// Результат: [10, 20, 30]Promise.all сохраняет порядок результатов по исходному массиву промисов. Если один промис отклонится, общий промис тоже отклонится. Уже запущенные операции при этом автоматически не отменяются.
Большую очередь запросов обрабатывайте с ограничением одновременных операций. Promise.all сам такого ограничения не задает.
Производительность методов перебора
Методы с полным обходом обрабатывают элементы массива, а создание результата требует дополнительной памяти. Разница важнее на очень больших массивах и в горячих циклах – участках, которые выполняются многократно.
Для обычных списков выбирайте метод по смыслу.
Цикл for дает контроль над индексом, остановкой и количеством действий. for...of сохраняет управление, но делает код короче. Цепочка filter().map() создает промежуточный массив и проходит отобранные элементы повторно.
Прежде чем переписывать такую цепочку, найдите узкое место профилировщиком. Стоимость запроса или сложного колбэка может превышать накладные расходы самого обхода.
Измеряйте конкретную задачу в целевой среде на одинаковых данных. Уберите console.log из измеряемого участка и повторите измерения после прогрева. Результат одного браузера нельзя автоматически переносить на другую среду.
Ошибки при переборе массива
Ошибки чаще возникают из-за неверного ожидания от метода. Сверяйте возвращаемое значение, действия колбэка и поведение разреженного массива.
Изменение массива во время forEach
Замена значений по существующим индексам сама по себе не сдвигает элементы.
const numbers = [1, 2, 3];
numbers.forEach((number, index, array) => {
array[index] = number * 2;
});
console.log(numbers);
// Результат: [2, 4, 6]Такой код меняет исходный массив. Для отдельного массива результатов используйте map. Однако map не копирует вложенные объекты автоматически: они могут оставаться общими для обоих массивов.
const users = [{ name: 'Анна' }];
const copied = users.map((user) => user);
copied[0].name = 'Вера';
console.log(users[0].name);
// Результат: ВераСтруктурные изменения опаснее: удаление элемента со сдвигом может пропустить соседнее значение.
const numbers = [1, 2, 3];
const visited = [];
numbers.forEach((number, index, array) => {
visited.push(number);
if (index === 0) {
array.shift();
}
});
console.log(visited);
// Результат: [1, 3]
console.log(numbers);
// Результат: [2, 3]После удаления первого элемента число 2 перемещается на индекс 0. Следующая итерация уже читает индекс 1, где находится 3.
forEach фиксирует длину перед началом обхода. Добавленные за исходной границей элементы он не посещает. Измененные значения внутри границы метод читает при достижении соответствующего индекса.
Для удаления элементов безопаснее создать результат через filter, не меняя источник внутри колбэка.
const numbers = [1, 2, 3];
const remaining = numbers.filter((number) => number !== 1);
console.log(remaining);
// Результат: [2, 3]
console.log(numbers);
// Результат: [1, 2, 3]map без return
const numbers = [1, 2, 3];
const doubled = numbers.map((number) => {
number * 2;
});
console.log(doubled);
// Результат: [undefined, undefined, undefined]Стрелочная функция с фигурными скобками требует явного return. Для побочного эффекта выбирайте forEach, чтобы не создавать ненужный массив через map.
Асинхронный колбэк в forEach
Асинхронный колбэк не превращает forEach в ожидаемую цепочку операций. Используйте for...of с await, если действия зависят друг от друга. Для независимых операций соберите промисы через map и дождитесь Promise.all.
Разреженные массивы
Пустая позиция массива отличается от существующего элемента со значением undefined. Примеры предполагают, что прототип не содержит свойств с соответствующими индексами.
const sparse = [1, , 3];
for (const value of sparse) {
console.log(value);
}
sparse.forEach((value) => console.log(value));
// Результат for...of: 1, undefined, 3; forEach: 1, 3Обычный индексный for проходит все позиции до length. Чтение отсутствующего элемента дает undefined, как при for...of.
map пропускает вызов колбэка для пустой позиции, но сохраняет ее в результате. Длина нового массива тоже сохраняется. filter собирает посещенные подходящие элементы без дырок.
const sparse = [1, , 3];
const mapped = sparse.map((value) => value * 2);
const filtered = sparse.filter(() => true);
console.log(mapped.length, Object.hasOwn(mapped, 1));
// Результат: 3 false
console.log(mapped[1]);
// Результат: undefined при чтении отсутствующей позиции
console.log(filtered);
// Результат: [1, 3]| Способ | Поведение пустых позиций |
|---|---|
Индексный for без дополнительных проверок | Проходит позиции; чтение дырки дает undefined |
for...of | Выдает undefined на месте дырки |
forEach, some, every | Не вызывают колбэк для дырок |
map | Пропускает колбэк, сохраняет длину и дырки |
filter | Пропускает дырки, собирает плотный результат |
reduce | Пропускает дырки; без начального значения ищет первый существующий элемент |
find, findIndex, findLast, findLastIndex | Вызывают колбэк для дырок со значением undefined |
Отказ от var
В примерах используются const и let. Они ограничивают область видимости переменной блоком, поэтому уменьшают риск случайного переиспользования счетчика. Объявление var не создает такую блочную область видимости.
Как выбрать способ перебора массива под задачу
Сначала определите ограничения обработки: порядок действий, возможность остановки и допустимость изменений источника.
- Если обработка зависит от предыдущего элемента или требует остановки, используйте
for...of. - Если нужен обратный проход или нестандартный шаг индекса, берите
for. - Если результат нужен для дальнейшей обработки, возвращайте его через
map,filterилиreduce. - Если достаточно ответа «да» или «нет», используйте
someлибоevery: они остановятся после определения ответа. - Если нужен найденный элемент, выбирайте
find; для его позиции используйтеfindIndexи сравнение с-1. - Если асинхронные действия зависят друг от друга, ожидайте их последовательно через
for...of. Для независимых действий используйтеPromise.allсmap.
Для собственных перечисляемых строковых свойств объекта удобно использовать Object.entries. Добавляйте for...in, когда задача требует учитывать цепочку прототипов.
Совет от нашей редакции: перед выбором метода запишите ожидаемый результат на маленьком массиве. Добавьте пустой массив и пропуск элемента – такие примеры помогают заметить неверные ожидания от обхода.
Популярное за неделю
- Как создать сайт самому в 2026: 4 способа + пошаговая инструкция 34 мин чтения
- Лучшие конструкторы для создания сайтов — плюсы, минусы и сравнения 22 мин чтения
- Скрипт сокращения URL на PHP с INI 3 мин чтения
- jquery select onchange в jQuery: как получить значение select 6 мин чтения
- Как создать фотогалерею для сайта 5 мин чтения
- Валидация формы js для регистрации с проверкой полей 5 мин чтения
Комментарии