forEach()
方法对数组的每个元素执行一次提供的函数。
The source for this interactive example is stored in a GitHub repository. If you'd like to contribute to the interactive examples project, please clone https://github.com/mdn/interactive-examples and send us a pull request.
arr.forEach(callback[, thisArg]);
callback
currentValue
index
可选array
可选forEach()
方法正在操作的数组。thisArg
可选this
的值(参考对象)。forEach
方法按升序为数组中含有效值的每一项执行一次callback
函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。
callback
函数会被依次传入三个参数:
如果给 forEach()
传递了 thisArg
参数,当调用时,它将被传给 callback
函数,作为它的 this
值。否则,将会传入 undefined
作为它的 this
值。callback
函数最终可观察到 this
值,这取决于函数观察到 this
的常用规则。
forEach
遍历的范围在第一次调用 callback
前就会确定。调用 forEach
后添加到数组中的项不会被 callback
访问到。如果已经存在的值被改变,则传递给 callback
的值是 forEach
遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()
),之后的元素将被跳过 - 参见下面的示例。
forEach()
为每个数组元素执行callback函数;不像 map()
或者 reduce()
,它总是返回 undefined
值,并且不可链式调用。典型用例是在一个链的最后执行副作用。
forEach()
does not mutate the array on which it is called (although callback
, if invoked, may do so).
注意: 没有办法中止或者跳出 forEach()
循环,除了抛出一个异常。如果你需要这样,使用 forEach()
方法是错误的。
若你需要提前终止循环,你可以使用:
Array.prototype.every()
Array.prototype.some()
Array.prototype.find()
Array.prototype.findIndex()
这些数组方法可以对数组元素判断,以便确定是否需要继续遍历:every()
,some()
,find()
,findIndex()
译者注:若条件允许,也可以使用 filter()
提前过滤出需要遍历的部分,再用 forEach()
处理。
const items = ['item1', 'item2', 'item3'];
const copy = [];
// before
for (let i=0; i<items.length; i++) {
copy.push(items[i]);
}
// after
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);
// logs:
// 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(function(entry) {
this.sum += entry;
++this.count;
}, this);
//console.log(this);
};
var obj = new Counter();
obj.add([1, 3, 5, 7]);
obj.count;
// 4 === (1+1+1+1)
obj.sum;
// 16 === (1+3+5+7)
因为 thisArg
参数(this
)传给了 forEach()
,每次调用时,它都被传给 callback
函数,作为它的 this
值。
下面的代码会创建一个给定对象的副本。 创建对象的副本有不同的方法,以下是只是一种方法,并解释了 Array.prototype.forEach()
是如何使用 ECMAScript 5 Object.*
元属性(meta property )函数工作的。
function copy(obj) {
var copy = Object.create(Object.getPrototypeOf(obj));
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
Object.defineProperty(copy, name, desc);
});
return copy;
}
var obj1 = { a: 1, b: 2 };
var obj2 = copy(obj1); // obj2 looks like obj1 now
下面的例子会输出"one", "two", "four"。当到达包含值"two"的项时,整个数组的第一个项被移除了,这导致所有剩下的项上移一个位置。因为元素 "four"现在在数组更前的位置,"three"会被跳过。 forEach()
不会在迭代之前创建数组的副本。
var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
console.log(word);
if (word === 'two') {
words.shift();
}
});
// one
// two
// four
forEach
是在第五版本里被添加到 ECMA-262 标准的;这样它可能在标准的其他实现中不存在,你可以在你调用 forEach
之前 插入下面的代码,在本地不支持的情况下使用 forEach()
。该算法是 ECMA-262 第5版中指定的算法。算法假定 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 = thisArg;
}
// 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) Array.prototype.forEach |
Standard | Initial definition. Implemented in JavaScript 1.6. |
ECMAScript 2015 (6th Edition, ECMA-262) Array.prototype.forEach |
Standard | |
ECMAScript Latest Draft (ECMA-262) Array.prototype.forEach |
Draft |
Desktop | Mobile | Server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
forEach | Chrome Full support Yes | Edge Full support 12 | 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 |