--- title: Array.prototype.forEach() slug: Web/JavaScript/Reference/Global_Objects/Array/forEach tags: - Array - ECMAScript5 - JavaScript - Method - Prototype - Reference - forEach - polyfill translation_of: Web/JavaScript/Reference/Global_Objects/Array/forEach ---
Метод forEach()
выполняет указанную функцию один раз для каждого элемента в массиве.
Источник этого интерактивного примера хранится в GitHub. Если вы хотите внести вклад в проект интерактивных примеров, пожалуйста, клонируйте https://github.com/mdn/interactive-examples и отправьте нам pull request.
arr.forEach(function callback(currentValue, index, array) { //your iterator }[, thisArg]);
callback
currentValue
index
{{optional_inline}}array
{{optional_inline}}thisArg
this
при вызове функции callback
.{{jsxref("undefined")}}.
Метод forEach()
выполняет функцию callback
один раз для каждого элемента, находящегося в массиве в порядке возрастания. Она не будет вызвана для удалённых или пропущенных элементов массива. Однако, она будет вызвана для элементов, которые присутствуют в массиве и имеют значение {{jsxref("Global_Objects/undefined", "undefined")}}.
Функция callback
будет вызвана с тремя аргументами:
Если в метод forEach()
был передан параметр thisArg
, при вызове callback
он будет использоваться в качестве значения this
. В противном случае, в качестве значения this
будет использоваться значение {{jsxref("Global_Objects/undefined", "undefined")}}. В конечном итоге, значение this
, наблюдаемое из функции callback
, определяется согласно {{jsxref('Operators/this', 'обычным правилам определения this
, видимого из функции')}}.
Диапазон элементов, обрабатываемых методом forEach()
, устанавливается до первого вызова функции callback
. Элементы, добавленные в массив после начала выполнения метода forEach()
, не будут посещены функцией callback
. Если существующие элементы массива изменятся, значения, переданные в функцию callback
, будут значениями на тот момент времени, когда метод forEach()
посетит их; удалённые элементы посещены не будут. Если уже посещённые элементы удаляются во время итерации (например, с помощью {{jsxref("Array.prototype.shift()", "shift()")}}), последующие элементы будут пропущены. ({{jsxref('Global_Objects/Array/forEach', 'Смотри пример ниже', 'Модификация_массива_во_время_итерации')}})
Примечание: Не существует способа остановить или прервать цикл forEach()
кроме как выбрасыванием исключения. Если вам необходимо такое поведение, метод forEach()
неправильный выбор.
Досрочное прекращение может быть достигнуто с:
Если нужно протестировать элементы массива на условие и нужно вернуть булево значение, вы можете воспользоваться методами {{jsxref("Array.prototype.every()", "every()")}}, {{jsxref("Array.prototype.some()", "some()")}}, {{jsxref("Array.prototype.find()", "find()")}} или {{jsxref("Array.prototype.findIndex()", "findIndex()")}}.
Метод forEach()
выполняет функцию callback
один раз для каждого элемента массива; в отличие от методов {{jsxref("Array.prototype.every()", "every()")}} и {{jsxref("Array.prototype.some()", "some()")}}, он всегда возвращает значение {{jsxref("Global_Objects/undefined", "undefined")}}.
const arraySparse = [1,3,,7] let numCallbackRuns = 0 arraySparse.forEach((element) => { console.log(element) numCallbackRuns++ }) console.log("numCallbackRuns: ", numCallbackRuns) // 1 // 3 // 7 // numCallbackRuns: 3 // комментарий: как вы видите пропущенное значение между 3 и 7 не вызывало функцию callback.
const items = ['item1', 'item2', 'item3'] const copy = [] // до for (let i = 0; i < items.length; i++) { copy.push(items[i]) } // после items.forEach(function(item){ copy.push(item) })
Примечание: Для отображения содержимого массива в консоли вы можете использовать console.table()
, который выводит отформатированную версию массива.
Следующий пример иллюстрирует альтернативный подход, использующий forEach()
.
Следующий код выводит каждый элемент массива на новой строке журнала:
function 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
Следующий (надуманный) пример обновляет свойства объекта, когда перебирает записи массива:
function Counter() { this.sum = 0 this.count = 0 } Counter.prototype.add = function(array) { array.forEach((entry) => { this.sum += entry ++this.count }, this) // ^---- Note } const obj = new Counter() obj.add([2, 5, 9]) obj.count // 3 obj.sum // 16
Поскольку в forEach()
передан параметр thisArg
(this
), он затем передаётся в callback
при каждом вызове. И callback использует его в качестве собственного значения this
.
Примечание: Если при передаче callback функции используется {{jsxref('Functions/Arrow_functions', 'выражение стрелочной функции')}}, параметр thisArg
может быть опущен, так как все стрелочные функции лексически привязываются к значению{{jsxref("Operators/this", "this")}}.
Следующий код использует {{jsxref("Array.prototype.every()")}} для логирования содержимого массива и останавливается при превышении значением заданного порогового значения THRESHOLD
.
var THRESHOLD = 12; var v = [5, 2, 16, 4, 3, 18, 20]; var res; res = v.every(function(element, index, array) { console.log('element:', element); if (element >= THRESHOLD) { return false; } return true; }); console.log('res:', res); // логи: // element: 5 // element: 2 // element: 16 // res: false res = v.some(function(element, index, array) { console.log('element:', element); if (element >= THRESHOLD) { return true; } return false; }); console.log('res:', res); // логи: // element: 5 // element: 2 // element: 16 // res: true
Следующий код создаёт копию переданного объекта. Существует несколько способов создания копии объекта, и это один из них. Он позволяет понять, каким образом работает Array.prototype.forEach()
, используя функции мета-свойств Object.*
из ECMAScript 5.
function copy(o) { var copy = Object.create(Object.getPrototypeOf(o)); var propNames = Object.getOwnPropertyNames(o); propNames.forEach(function(name) { var desc = Object.getOwnPropertyDescriptor(o, name); Object.defineProperty(copy, name, desc); }); return copy; } var o1 = { a: 1, b: 2 }; var o2 = copy(o1); // теперь o2 выглядит также, как и o1
В следующем примере в лог выводится "one"
, "two"
, "four"
.
При достижении записи, содержащей значение 'two'
, первая запись всего массива удаляется, в результате чего все оставшиеся записи перемещаются на одну позицию вверх. Поскольку элемент 'four'
теперь находится на более ранней позиции в массиве, 'three'
будет пропущен.
forEach()
не делает копию массива перед итерацией.
let words = ['one', 'two', 'three', 'four'] words.forEach((word) => { console.log(word) if (word === 'two') { words.shift() } }) // one // two // four
Следующий пример приведён только для целей обучения. Если вы хотите выравнять массив с помощью встроенных методов, вы можете использовать {{jsxref("Array.prototype.flat()")}}
function flatten(arr) { const result = [] arr.forEach((i) => { if (Array.isArray(i)) { result.push(...flatten(i)) } else { result.push(i) } }) return result } // Usage const nested = [1, 2, 3, [4, 5, [6, 7], 8, 9]] flatten(nested) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Метод forEach()
был добавлен к стандарту ECMA-262 в 5-м издании; поэтому он может отсутствовать в других реализациях стандарта. Вы можете работать с ним, добавив следующий код в начало ваших скриптов, он позволяет использовать forEach()
в реализациях, которые не поддерживают этот метод. Этот алгоритм является точно тем, что описан в ECMA-262 5-го издания; он предполагает, что {{jsxref("Object")}} и {{jsxref("TypeError")}} имеют свои первоначальные значения и что callback.call
вычисляется в оригинальное значение {{jsxref("Function.prototype.call()")}}.
// Шаги алгоритма ECMA-262, 5-е издание, 15.4.4.18 // Ссылка (en): http://es5.github.io/#x15.4.4.18 // Ссылка (ru): http://es5.javascript.ru/x15.4.html#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. Положим O равным результату вызова ToObject passing the |this| value as the argument. var O = Object(this); // 2. Положим lenValue равным результату вызова внутреннего метода Get объекта O с аргументом "length". // 3. Положим len равным ToUint32(lenValue). var len = O.length >>> 0; // 4. Если IsCallable(callback) равен false, выкинем исключение TypeError. // Смотрите: http://es5.github.com/#x9.11 if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } // 5. Если thisArg присутствует, положим T равным thisArg; иначе положим T равным undefined. if (arguments.length > 1) { T = thisArg; } // 6. Положим k равным 0 k = 0; // 7. Пока k < len, будем повторять while (k < len) { var kValue; // a. Положим Pk равным ToString(k). // Это неявное преобразование для левостороннего операнда в операторе in // b. Положим kPresent равным результату вызова внутреннего метода HasProperty объекта O с аргументом Pk. // Этот шаг может быть объединён с шагом c // c. Если kPresent равен true, то if (k in O) { // i. Положим kValue равным результату вызова внутреннего метода Get объекта O с аргументом Pk. kValue = O[k]; // ii. Вызовем внутренний метод Call функции callback с объектом T в качестве значения this и // списком аргументов, содержащим kValue, k и O. callback.call(T, kValue, k, O); } // d. Увеличим k на 1. k++; } // 8. Вернём undefined. }; }
{{Compat}}