array.forEach

array.forEach

forEach()方法对数组的每个元素执行一次提供的函数。

var a = ['a', 'b', 'c']; a.forEach(function(element) { console.log(element } // a // b // c

语法

arr.forEach(function callback(currentValue, index, array) { //your iterator }[, thisArg]

参数

callback为数组中每个元素执行的函数,该函数接收三个参数:

执行回调函数时使用this的值(即参考Object)。

返回值

undefined.

描述

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()不改变它被调用的数组(虽然执行callback,但如果调用可能也会这样做)。

没有办法中止或者跳出 forEach() 循环,除了抛出一个异常。如果你需要这样,使用forEach()方法是错误的,你可以用一个简单的循环作为替代。如果您正在测试一个数组里的元素是否符合某条件,且需要返回一个布尔值,那么可使用 every()some()。如果可用,新方法find()或者findIndex()也可被用于真值测试的提早终止。

示例

转换为forEach

之前

var items = ['item1', 'item2', 'item3']; var copy = []; for (var i=0; i<items.length; i++) { copy.push(items[i]) }

之后

var items = ['item1', 'item2', 'item3']; var copy = []; items.forEach(function(item){ copy.push(item) }

打印出数组的内容

下面的代码会为每一个数组元素输出一行记录:

function logArrayElements(element, index, array) { console.log('a[' + index + '] = ' + element } // Notice that index 2 is skipped since there is no item at // that position in the array. [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 // ^---- Note }; var obj = new Counter( obj.add([2, 5, 9] obj.count; // 3 obj.sum; // 16

因为thisArg参数 (this) 传给了forEach(),每次调用时,它都被传给callback函数,作为它的this值。

如果使用箭头函数表达式传入函数参数,thisArg参数会被忽略,因为箭头函数在词法上绑定了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

兼容旧环境(Polyfill)

forEach 是在第五版本里被添加到 ECMA-262 标准的;这样它可能在标准的其他实现中不存在,你可以在你调用forEach之前 插入下面的代码,在本地不支持的情况下使用forEach()。该算法是 ECMA-262 第5版中指定的算法。算法假定ObjectTypeError拥有它们的初始值。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. }; }

规范

SpecificationStatusComment
ECMAScript 5.1 (ECMA-262)The definition of 'Array.prototype.forEach' in that specification.StandardInitial definition. Implemented in 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.Living Standard

浏览器兼容性

FeatureChromeEdgeFirefoxInternet ExplorerOperaSafari
Basic Support(Yes)(Yes)1.59(Yes)(Yes)

FeatureAndroidChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
Basic Support(Yes)(Yes)(Yes)1(Yes)(Yes)(Yes)