Метод forEach()
виконує надану функцію один раз для кожного елемента масиву.
var arr = ['a', 'b', 'c']; arr.forEach(function(element) { console.log(element); }); // a // b // c
Синтаксис
arr.forEach(function callback(currentValue, index, array) { … }[, thisArg]);
Параметри
callback
- Функція, що виконується для кожного елемента. Приймає три аргументи:
-
currentValue
- Значення чергового елемента масиву.
index
Optional- Індекс чергового елемента в масиві.
array
Optional- Масив, до якого застосовано
forEach()
.
thisArg
Optional-
Значення, що використовується як
this
коли викликаєтьсяcallback
.
Вертає
Опис
Метод forEach()
перебирає всі елементи масиву за зростанням індексу та викликає для кожного функцію callback
. Оминає властивості, які було видалено або не було започатковано — в розріджених масивах.
Функція callback
викликається з трьома аргументами:
- значення елемента;
- індекс елемента;
- масив, що перебирається.
Якщо для forEach()
вказано параметр thisArg
, його буде використано як this
для функції callback
. Якщо ж не вказано, то буде використано значення undefined
. Зрештою значення this
для функції callback
визначатиметься відповідно до загальних правил.
Множина індексів елементів, що їх перебиратиме forEach()
з'ясовується ще до першого виклику callback
. Елементи, додані після здійснення виклику forEach()
, буде знехтувано (callback
для жодного з них не викликатиметься). Якщо змінити значення котрогось зі ще не відвіданих елементів масиву, зміни буде враховано — до функції callback
потрапить те значення елемента, яке він мав безпосередньо перед відповідним викликом callback
. Якщо елемент видалено до відвідування, його відвідано не буде. Якщо вже відвіданий елемент видалено упродовж перебирання (наприклад, за допомогою shift()
), індекси подальших елементів зменшаться на одиницю, а отже певний елемент буде пропущено — дивіться приклади нижче у статті.
На відміну від map()
чи reduce()
, метод forEach()
завжди вертає значення undefined
, тож продовжити ланцюжок викликів після нього неможливо. Досить типовим є виклик forEach()
наприкінці ланцюжка методів з метою виконання додаткових дій.
Сам метод forEach()
не змінює масив, на якому його викликано, втім усередині функції callback
це можливо.
Заувага: Зупинити чи перервати цикл forEach()
неможливо без викидання винятку. Якщо вам це потрібно, метод forEach()
— не ліпший вибір. Скористайтеся натомість звичайним циклом. Якщо ви перевіряєте елементи масиву на відповідність певній умові та маєте потребу повернути значення типу Boolean, зверніть увагу на методи every()
та some()
. Також можна скористатись новими методами find()
та findIndex()
, якщо вони доступні, — в цих методах перебір елементів переривається, якщо чергове значення відповідає умові.
Приклади
Перехід від for до forEach
Було:
const items = ['щось', 'то', 'має', 'бути']; const copy = []; for (let i = 0; i < items.length; i++) { copy.push(items[i]) }
Стане:
const items = ['щось', 'то', 'має', 'бути']; const copy = []; items.forEach(function(item) { copy.push(item) });
Друкування вмісту масиву
Наведений код виводить у консоль індекс та значення кожного елемента масиву:
function logArrayElements(element, index, array) { console.log('array[' + index + '] = ' + element); } // Завважте, що індекс 2 буде пропущено, // позаяк елемента на тому місці в масиві немає. [2, 5, , 9].forEach(logArrayElements); // Буде виведено у консоль: // array[0] = 2 // array[1] = 5 // array[3] = 9
Використання thisArg
Наведений приклад змінює властивості об'єкта відповідно до кожного елемента в отриманому масиві:
function Counter() { this.sum = 0; this.count = 0; } Counter.prototype.add = function(array) { array.forEach(function(entry) { this.sum += entry; this.count++; }, this); // ^---- Зверніть увагу! }; const obj = new Counter(); obj.add([2, 5, 9]); obj.count; // 3 obj.sum; // 16
Оскільки для forEach()
вказано параметр thisArg
, для кожного виклику callback
(тут безіменної функції) він вживатиметься як this
.
Заувага: Якщо передавати перший аргумент forEach() за допомогою стрілкового запису функції, то параметр thisArg
можна не вказувати, позаяк стрілкова функція сама захоплює значення this
.
Функція копіювання об'єкта
Існує чимало способів створення копії об'єкта. Наведений приклад є лише одним з них і насправді призначений лише для наочного пояснення того, як працює Array.prototype.forEach()
на прикладі використання нових функцій ECMAScript 5 з Object.*
для роботи з керованими властивостями:
function copy(obj) { const copy = Object.create(Object.getPrototypeOf(obj)); const propNames = Object.getOwnPropertyNames(obj); propNames.forEach(function(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
Якщо масив змінено під час перебору, деякі елементи може бути пропущено
Наведений приклад виводить у консоль послідовно "перший", "другий" та "четвертий". Коли перебір сягне другого елемента (що має значення "другий"), виклик words.shift()
видалить перший елемент масиву, а всі, що лишаться, посунуться на одне місце ліворуч — "четвертий" стане наступним (після поточного) і "третій" таким чином буде пропущено:
var words = ['перший', 'другий', 'третій', 'четвертий']; words.forEach(function(word) { console.log(word); if (word === 'другий') { words.shift(); } }); // перший // другий // четвертий
Метод forEach()
не створює копії масиву перед перебором, а лише з'ясовує множину індексів, що їх буде перебрано.
Запасний варіант (поліфіл)
Цей метод було стандартизовано 5-им випуском ECMA-262. Для рушіїв, що не мають підтримки цього метода, стане в нагоді наведене нижче рішення. Цей алгоритм точнісінько відповідає вимогам 5-го випуску ECMA-262 за умови, що Object
і TypeError
не було змінено, а виклик callback.call()
відповідає очікуваному Function.prototype.call()
:
// Production steps of ECMA-262, Edition 5, 15.4.4.18 // Reference: http://es5.github.io/#x15.4.4.18 if (!Array.prototype.forEach) { Array.prototype.forEach = function(callback/*, thisArg*/) { var T, k; if (this == null) { throw new TypeError('this is null or not defined'); } // 1. Let O be the result of calling toObject() passing the // |this| value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get() internal // method of O with the argument "length". // 3. Let len be toUint32(lenValue). var len = O.length >>> 0; // 4. If isCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } // 5. If thisArg was supplied, let T be thisArg; else let // T be undefined. if (arguments.length > 1) { T = arguments[1]; } // 6. Let k be 0. k = 0; // 7. Repeat while k < len. while (k < len) { var kValue; // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator. // b. Let kPresent be the result of calling the HasProperty // internal method of O with argument Pk. // This step can be combined with c. // c. If kPresent is true, then if (k in O) { // i. Let kValue be the result of calling the Get internal // method of O with argument Pk. kValue = O[k]; // ii. Call the Call internal method of callback with T as // the this value and argument list containing kValue, k, and O. callback.call(T, kValue, k, O); } // d. Increase k by 1. k++; } // 8. return undefined. }; }
Специфікації
Специфікація | Статус | Коментар |
---|---|---|
ECMAScript 5.1 (ECMA-262) The definition of 'Array.prototype.forEach' in that specification. |
Standard | Початкова виознака. Запроваджено у JavaScript 1.6. |
ECMAScript 2015 (6th Edition, ECMA-262) The definition of 'Array.prototype.forEach' in that specification. |
Standard | |
ECMAScript Latest Draft (ECMA-262) The definition of 'Array.prototype.forEach' in that specification. |
Draft |
Підтримка веб-переглядачами
Desktop | Mobile | Server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Basic support | Chrome Full support Yes | Edge Full support Yes | Firefox Full support 1.5 | IE Full support 9 | Opera Full support Yes | Safari Full support Yes | WebView Android Full support Yes | Chrome Android Full support Yes | Edge Mobile Full support Yes | Firefox Android Full support 4 | Opera Android Full support Yes | Safari iOS Full support Yes | Samsung Internet Android Full support Yes | nodejs Full support Yes |
Legend
- Full support
- Full support