Array.prototype.forEach()
Метод forEach()
("для кожного") примірників Array
виконує передану функцію один раз для кожного елементу масиву.
Спробуйте його в дії
Синтаксис
forEach(callbackFn)
forEach(callbackFn, thisArg)
Параметри
callbackFn
Функція до виконання для кожного елемента масиву. Її повернене значення - відкидається. Ця функція викликається із наступними аргументами:
element
Поточний елемент масиву, який опрацьовується.
index
Індекс поточного елемента масиву, що опрацьовується.
array
Власне масив, на якому було викликано
forEach()
.
thisArg
Необов'язковеЗначення для використання за
this
при виконанніcallbackFn
. Докладніше про це в ітеративних методах.
Повернене значення
Жодного (undefined
).
Опис
Метод forEach()
є ітеративним методом. Він викликає передану функцію callbackFn
на кожному елементі масиву, в порядку зростання індексів. На відміну від map()
, forEach()
завжди повертає undefined
і не може бути проміжною ланкою ланцюжка. Типове його використання – для виконання побічних ефектів у кінці ланцюжка. Більше про те, як загалом працюють такі методи, читайте в розділі ітеративних методів.
callbackFn
закликається лише для тих індексів масиву, що мають присвоєні значення. Вона не закликається для порожніх комірок у розріджених масивах.
Метод forEach()
є узагальненим. Він лишень очікує, що значення this
матиме властивість length
, а також властивості з цілочисловими ключами.
Немає іншого способу зупинити чи перервати цикл forEach()
, окрім викидання винятку. Якщо потрібна логіка з перериванням, то метод forEach()
– негодящий інструмент.
Раннього завершення можна досягнути з інструкціями циклів, як то for
, for...of
і for...in
. Методи масивів, як то every()
, some()
, find()
і {{jsxref("Array/findIndex", "findIndex()")}, також відразу зупиняють ітерацію, коли подальше ітерування стає непотрібним.
forEach()
розраховує на синхронну функцію: він не очікує на проміси. Слід взяти до уваги можливі наслідки при використанні промісів (чи асинхронних функцій) у функціях зворотного виклику для forEach
.
const ratings = [5, 4, 5];
let sum = 0;
const sumFunction = async (a, b) => a + b;
ratings.forEach(async (rating) => {
sum = await sumFunction(sum, rating);
});
console.log(sum);
// Наївно очікуваний вивід: 14
// Фактичний вивід: 0
Про виконання низки асинхронних операцій, послідовно чи паралельно, дивіться композицію промісів.
Приклади
Перетворення циклу for на forEach
const items = ["item1", "item2", "item3"];
const copyItems = [];
// до
for (let i = 0; i < items.length; i++) {
copyItems.push(items[i]);
}
// після
items.forEach((item) => {
copyItems.push(item);
});
Друк вмісту масиву
Примітка: Щоб показати вміст масиву у консолі, можна застосувати метод
console.table()
, який друкує відформатований варіант масиву.Приклад далі ілюструє альтернативний підхід, із застосуванням
forEach()
.
Наступний код друкує рядок для кожного елементу в масиві:
const logArrayElements = (element, index /*, array */) => {
console.log(`a[${index}] = ${element}`);
};
// Зауважте, що порядковий номер 2 пропущено, оскільки в масиві не існує
// елементу на цій позиції.
[2, 5, , 9].forEach(logArrayElements);
// Друкує:
// a[0] = 2
// a[1] = 5
// a[3] = 9
Застосування thisArg
Наступний (надуманий) приклад оновлює властивості об'єкта, з урахуванням поданих елементів масиву:
class Counter {
constructor() {
this.sum = 0;
this.count = 0;
}
add(array) {
// Лише вирази функцій мають власні зв'язування this.
array.forEach(function countEntry(entry) {
this.sum += entry;
++this.count;
}, this);
}
}
const obj = new Counter();
obj.add([2, 5, 9]);
console.log(obj.count); // 3
console.log(obj.sum); // 16
Оскільки параметр thisArg
(this
) було задано в forEach()
, він передавався до функції callback
кожного разу, коли вона викликалась. Сама функція зворотного виклику використовує те саме значення this
.
Примітка: Якщо передачу функції зворотного виклику було використано із застосуванням виразу стрілкової функції, то значення параметра
thisArg
можна опустити, оскільки всі стрілкові функції прив'язують значенняthis
лексично.
Функція копіювання об'єкта
Наступний код створює копію поданого об'єкта.
Існують різні способи створити копію об'єкта. Спосіб, що наведено нижче - це лише один із них, покликаний показати, як працює Array.prototype.forEach()
шляхом використання службових функцій Object.*
.
const copy = (obj) => {
const copy = Object.create(Object.getPrototypeOf(obj));
const propNames = Object.getOwnPropertyNames(obj);
propNames.forEach((name) => {
const desc = Object.getOwnPropertyDescriptor(obj, name);
Object.defineProperty(copy, name, desc);
});
return copy;
};
const obj1 = { a: 1, b: 2 };
const obj2 = copy(obj1); // obj2 тепер має точнісінько такий самий вигляд, як obj1
Сплощення масиву
Приклад нижче наведено лише для навчальних потреб. Для сплощення масивів вбудованими методами можна застосовувати Array.prototype.flat()
.
const flatten = (arr) => {
const result = [];
arr.forEach((item) => {
if (Array.isArray(item)) {
result.push(...flatten(item));
} else {
result.push(item);
}
});
return result;
};
// Застосування
const nested = [1, 2, 3, [4, 5, [6, 7], 8, 9]];
console.log(flatten(nested)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Використання третього аргументу callbackFn
Аргумент array
корисний тоді, коли є потреба звернутися до іншого елемента масиву, особливо коли немає змінної, що посилається на цей масив. У наступному прикладі спочатку використовується filter()
для видобування додатних значень, а потім forEach()
– для виведення їхніх сусідів.
const numbers = [3, -1, 1, 4, 1, 5];
numbers
.filter((num) => num > 0)
.forEach((num, idx, arr) => {
// Без аргументу arr немає способу легко отримати доступ до
// проміжного масиву без збереження його в змінній.
console.log(arr[idx - 1], num, arr[idx + 1]);
});
// undefined 3 1
// 3 1 4
// 1 4 1
// 4 1 5
// 1 5 undefined
Використання forEach() на розріджених масивах
const arraySparse = [1, 3, /* пропуск */, 7];
let numCallbackRuns = 0;
arraySparse.forEach((element) => {
console.log({ element });
numCallbackRuns++;
});
console.log({ numCallbackRuns });
// { element: 1 }
// { element: 3 }
// { element: 7 }
// { numCallbackRuns: 3 }
Функція зворотного виклику не закликається для пропущеного значення за індексом 2.
Виклик forEach() на об'єктах-немасивах
Метод forEach()
зчитує з this
властивість length
, а потім звертається до кожної властивості, чий ключ – невід'ємне ціле число, менше за length
.
const arrayLike = {
length: 3,
0: 2,
1: 3,
2: 4,
3: 5, // ігнорується forEach(), оскільки length – 3
};
Array.prototype.forEach.call(arrayLike, (x) => console.log(x));
// 2
// 3
// 4
Специфікації
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
forEach
|
Chrome Full support 1 | Edge Full support 12 | Firefox Full support 1.5 | Internet Explorer Full support 9 | Opera Full support 9.5 | Safari Full support 3 | WebView Android Full support 37 | Chrome Android Full support 18 | Firefox for Android Full support 4 | Opera Android Full support 10.1 | Safari on iOS Full support 1 | Samsung Internet Full support 1.0 | Deno Full support 1.0 | Node.js Full support 0.10.0 |