Як пройти по масиву циклом?
Коротка відповідь
- Потрібен індекс, контроль кроків, break/continue: класичний for.
- Потрібні лише значення, читабельність і можливість переривати: for...of.
- Просто виконати дію для кожного елемента без переривання: forEach.
- Отримати новий масив/значення: map, filter, reduce, some/every, find.
- Асинхронний послідовний обхід: for...of + await. Паралельно: Promise.all з map.
- Не використовуйте for...in для масивів (він для об'єктів, може обходити зайві властивості).
Детальний розбір
1) Індексний for, максимум контролю
Підходить, коли потрібен індекс, крок, ранній вихід, пропуски ітерацій і максимальна продуктивність на гарячих ділянках.
const arr = [10, 20, 30, 40];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 30) continue; // пропустити 30
if (arr[i] > 35) break; // перервати цикл
console.log(i, arr[i]); // індекс і значення
}2) for...of, зручний перебір значень
Простий синтаксис для значень, підтримує break/continue/return з обгортаючої функції. Для індексів використовуйте arr.entries().
const arr = ['a', 'b', 'c'];
for (const v of arr) {
if (v === 'b') continue; // пропустити
console.log(v);
}
// Індекс + значення через entries()
for (const [i, v] of arr.entries()) {
console.log(i, v);
}3) Array.prototype.forEach, без переривання
Виконує функцію для кожного елемента, але не можна зробити break/continue; return завершить лише колбек. Для раннього виходу використовуйте for/for...of.
const arr = [1, 2, 3];
arr.forEach((value, index) => {
// НЕМАЄ способу перервати весь forEach до кінця
console.log(index, value);
});4) while / do...while, коли умова первинна
Використовуються, коли ітерації контролюються умовою, а не довжиною масиву (наприклад, читання з черги).
const queue = [1, 2, 3];
while (queue.length) {
const item = queue.shift();
console.log(item);
}
do {
// виконається щонайменше один раз
} while (false);5) for...in, не для масивів
Перебирає перелічувані ключі об'єкта, включно зі успадкованими та рядковими ключами. Для масивів може дати несподіваний порядок і «зайві» властивості.
const arr = [10, 20];
arr.extra = 42; // додали властивість
for (const k in arr) {
console.log(k); // '0', '1', 'extra', не те, що очікували
}
// Замість цього використовуйте for, for...of або методи масиву.Функціональні методи: map / filter / reduce / some / every / find
Ідеальні, коли потрібен новий масив/значення зі старого. Вони не модифікують вихідний масив (крім рідкісних випадків з мутаціями всередині колбеку).
const users = [
{ id: 1, name: 'Ann', active: true },
{ id: 2, name: 'Bob', active: false },
{ id: 3, name: 'Cat', active: true },
];
const activeNames = users
.filter(u => u.active) // залишити активних
.map(u => u.name); // взяти імена
const hasInactive = users.some(u => !u.active); // true/false
const allActive = users.every(u => u.active); // true/false
const byId = users.reduce((acc, u) => {
acc[u.id] = u; // акумулюємо в об'єкт
return acc;
}, {});
const firstInactive = users.find(u => !u.active); // перший підхожийІндекс + значення
Якщо потрібен і індекс, і значення, використовуйте arr.entries() з for...of, або другий аргумент колбеку в forEach/map/filter.
const arr = ['x', 'y', 'z'];
for (const [i, v] of arr.entries()) {
console.log(i, v);
}
arr.forEach((v, i) => console.log(i, v));Переривання й пропуск ітерацій
break/continue працюють з for/for...of/while. У forEach та методах масиву вони недоступні (використовуйте умовні гілки чи інші конструкції).
const arr = [1, 2, 3, 4, 5];
for (const n of arr) {
if (n % 2 === 0) continue; // пропустити парні
if (n > 4) break; // зупинитися на 5
console.log(n);
}Асинхронні обходи
Для послідовних асинхронних операцій використовуйте for...of + await. Для паралельного виконання використовуйте map -> Promise.all. Не використовуйте await всередині forEach, він не чекає.
// Послідовно
async function processSequential(urls) {
for (const url of urls) {
const res = await fetch(url);
console.log(url, res.status);
}
}
// Паралельно
async function processParallel(urls) {
const responses = await Promise.all(urls.map(url => fetch(url)));
responses.forEach((res, i) => console.log(urls[i], res.status));
}
// Антипатерн: await у forEach
async function bad(urls) {
urls.forEach(async (url) => {
const res = await fetch(url); // не чекає завершення всіх
console.log(res.status);
});
// Функція завершиться до завершення всіх fetch
}Продуктивність і читабельність: тези
- На гарячих ділянках класичний for зазвичай трохи швидший, але різниця рідко критична.
- Обирайте найбільш читабельний варіант, що відповідає задачі (map/filter для перетворень, for...of для простого обходу).
- Уникайте мутацій масиву в процесі обходу (push/shift на вихідному масиві), якщо це не потрібно.
Шпаргалка вибору
- Потрібен новий масив зі старого: map/filter/flatMap.
- Потрібно акумулювати одне значення (сума, об'єкт, карта): reduce.
- Знайти/перевірити: find/some/every.
- Простий обхід значень з можливістю break: for...of.
- Індекс, крок, складні умови, продуктивність: класичний for.
- Асинхронно послідовно: for...of + await.
- Асинхронно паралельно: Promise.all + map.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.