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
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
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

Дивіться також