---
title: Array.prototype.forEach()
slug: Web/JavaScript/Reference/Global_Objects/Array/forEach
tags:
  - Array
  - ECMAScript5
  - JavaScript
  - 参考
  - 数组
  - 方法
translation_of: Web/JavaScript/Reference/Global_Objects/Array/forEach
---
<div>{{JSRef}}</div>

<p><code><strong>forEach()</strong></code> 方法对数组的每个元素执行一次给定的函数。</p>



<p>{{EmbedInteractiveExample("pages/js/array-foreach.html")}}</p>

<h2 id="语法">语法</h2>

<pre class="syntaxbox"><var>arr</var>.forEach(<var>callback(currentValue [, index [, array]])</var>[, <var>thisArg</var>])</pre>

<h3 id="参数">参数</h3>

<dl>
 <dt><code><var>callback</var></code></dt>
 <dd>为数组中每个元素执行的函数,该函数接收一至三个参数:
  <dl>
    <dt><code><var>currentValue</var></code></dt>
    <dd>数组中正在处理的当前元素。</dd>
    <dt><code><var>index</var></code> {{optional_inline}}</dt>
    <dd>数组中正在处理的当前元素的索引。</dd>
    <dt><code><var>array</var></code> {{optional_inline}}</dt>
    <dd><code>forEach()</code> 方法正在操作的数组。</dd>
  </dl>
 </dd>
 <dt><code><var>thisArg</var></code> {{optional_inline}}</dt>
 <dd>可选参数。当执行回调函数 <code><var>callback</var></code> 时,用作 <code>this</code> 的值。</dd>
</dl>

<h3 id="返回值">返回值</h3>

<p>{{jsxref("undefined")}}。</p>

<h2 id="描述">描述</h2>

<p><code>forEach()</code> 方法按升序为数组中含有效值的每一项执行一次 <code><var>callback</var></code> 函数,那些已删除或者未初始化的项将被跳过(例如在稀疏数组上)。</p>

<p>可依次向 <code><var>callback</var></code> 函数传入三个参数:</p>

<ol>
 <li>数组当前项的值</li>
 <li>数组当前项的索引</li>
 <li>数组对象本身</li>
</ol>

<p>如果 <code><var>thisArg</var></code> 参数有值,则每次 <code><var>callback</var></code> 函数被调用时,<code>this</code> 都会指向 <code><var>thisArg</var></code> 参数。如果省略了 <code><var>thisArg</var></code> 参数,或者其值为 <code>null</code> 或 <code>undefined</code>,<code>this</code> 则指向全局对象。按照<a href="/zh-CN/docs/Web/JavaScript/Reference/Operators/this">函数观察到 <code>this</code> 的常用规则</a>,<code><var>callback</var></code> 函数最终可观察到 <code>this</code> 值。</p>

<p><code>forEach()</code> 遍历的范围在第一次调用 <code><var>callback</var></code> 前就会确定。调用 <code>forEach</code> 后添加到数组中的项不会被 <code><var>callback</var></code> 访问到。如果已经存在的值被改变,则传递给 <code><var>callback</var></code> 的值是 <code>forEach()</code> 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 {{jsxref("Array.prototype.shift()", "shift()")}}),之后的元素将被跳过——<a href="#如果数组在迭代时被修改了,则其他元素会被跳过。">参见下面的示例</a>。</p>

<p><code>forEach()</code> 为每个数组元素执行一次 <code><var>callback</var></code> 函数;与 {{jsxref("Array.prototype.map()", "map()")}} 或者 {{jsxref("Array.prototype.reduce()", "reduce()")}} 不同的是,它总是返回 {{jsxref("undefined")}} 值,并且不可链式调用。其典型用例是在一个调用链的最后执行副作用(side effects,函数式编程上,指函数进行 返回结果值 以外的操作)。</p>

<p><code>forEach()</code> 被调用时,不会改变原数组,也就是调用它的数组(尽管 <code><var>callback</var></code> 函数在被调用时可能会改变原数组)。(译注:此处说法可能不够明确,具体可参考EMCA语言规范:'<code>forEach</code> does not directly mutate the object on which it is called but the object may be mutated by the calls to <code><var>callbackfn</var></code>.',即 <code>forEach</code> 不会直接改变调用它的对象,但是那个对象可能会被 <code><var>callback</var></code> 函数改变。)</p>

<div class="note">
<p><strong>备注:</strong> 除了抛出异常以外,没有办法中止或跳出 <code>forEach()</code> 循环。如果你需要中止或跳出循环,<code>forEach()</code> 方法不是应当使用的工具。</p>

<p>若你需要提前终止循环,你可以使用:</p>

<ul>
 <li>一个简单的 <a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/for">for</a> 循环</li>
 <li><a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/for...of">for...of</a> / <a href="/zh-CN/docs/Web/JavaScript/Reference/Statements/for...in">for...in</a> 循环</li>
 <li>{{jsxref("Array.prototype.every()")}}</li>
 <li>{{jsxref("Array.prototype.some()")}}</li>
 <li>{{jsxref("Array.prototype.find()")}}</li>
 <li>{{jsxref("Array.prototype.findIndex()")}}</li>
</ul>

<p>这些数组方法则可以对数组元素判断,以便确定是否需要继续遍历:</p>

<ul>
 <li>{{jsxref("Array.prototype.every()", "every()")}}</li>
 <li>{{jsxref("Array.prototype.some()", "some()")}}</li>
 <li>{{jsxref("Array.prototype.find()", "find()")}}</li>
 <li>{{jsxref("Array.prototype.findIndex()", "findIndex()")}}</li>
</ul>

<p>译者注:只要条件允许,也可以使用 {{jsxref("Array.prototype.filter()", "filter()")}} 提前过滤出需要遍历的部分,再用 <code>forEach()</code> 处理。</p>
</div>

<h2 id="示例">示例</h2>

<h3 id="不对未初始化的值进行任何操作(稀疏数组)">不对未初始化的值进行任何操作(稀疏数组)</h3>

<p>如你所见,<code>3</code> 和 <code>7</code> 之间空缺的数组单元未被 <code>forEach()</code> 调用 <code><var>callback</var></code> 函数,或进行任何其他操作。</p>

<pre class="brush: js">const arraySparse = [1,3,,7];
let numCallbackRuns = 0;

arraySparse.forEach(function(element){
  console.log(element);
  numCallbackRuns++;
});

console.log("numCallbackRuns: ", numCallbackRuns);

// 1
// 3
// 7
// numCallbackRuns: 3</pre>

<h3 id="将_for_循环转换为_forEach">将 for 循环转换为 forEach</h3>

<pre class="brush:js">const items = ['item1', 'item2', 'item3'];
const copy = [];

// before
for (let i=0; i&lt;items.length; i++) {
  copy.push(items[i]);
}

// after
items.forEach(function(item){
  copy.push(item);
});
</pre>

<h3 id="打印出数组的内容">打印出数组的内容</h3>

<div class="note">
<p><strong>备注:</strong>为了在控制台中显示数组的内容,你可以使用 <code><a href="/zh-CN/docs/Web/API/Console/table">console.table()</a></code> 来展示经过格式化的数组。下面的例子则是另一种使用 <code>forEach()</code> 的格式化的方法。</p>
</div>

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

<pre class="brush:js">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
</pre>

<h3 id="使用_thisArg">使用 <code><var>thisArg</var></code></h3>

<p>举个勉强的例子,按照每个数组中的元素值,更新一个对象的属性:</p>

<pre class="brush:js">function Counter() {
  this.sum = 0;
  this.count = 0;
}
Counter.prototype.add = function(array) {
  array.forEach(function(entry) {
    this.sum += entry;
    ++this.count;
  }, this);
  // ^---- Note
};

const obj = new Counter();
obj.add([2, 5, 9]);
obj.count;
// 3 === (1 + 1 + 1)
obj.sum;
// 16 === (2 + 5 + 9)
</pre>

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

<div>
<div class="note">
<p><strong>备注:</strong>如果使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭头函数表达式</a>来传入函数参数, <code><var>thisArg</var></code> 参数会被忽略,因为箭头函数在词法上绑定了 {{jsxref("Operators/this", "this")}} 值。</p>
</div>
</div>

<h3 id="对象复制器函数">对象复制器函数</h3>

<p>下面的代码会创建一个给定对象的副本。 创建对象的副本有不同的方法,以下是只是一种方法,并解释了 <code>Array.prototype.forEach()</code> 是如何使用 ECMAScript 5 <code>Object.*</code> 元属性(meta property)函数工作的。</p>

<pre class="brush: js">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 一模一样了
</pre>

<h3 id="如果数组在迭代时被修改了,则其他元素会被跳过。">如果数组在迭代时被修改了,则其他元素会被跳过。</h3>

<p>下面的例子会输出 "one", "two", "four"。当到达包含值 "two" 的项时,整个数组的第一个项被移除了,这导致所有剩下的项上移一个位置。因为元素 "four" 正位于在数组更前的位置,所以 "three" 会被跳过。 <code>forEach()</code> 不会在迭代之前创建数组的副本。</p>

<pre class="brush:js">var words = ['one', 'two', 'three', 'four'];
words.forEach(function(word) {
  console.log(word);
  if (word === 'two') {
    words.shift();
  }
});
// one
// two
// four
</pre>

<h3 id="扁平化数组">扁平化数组</h3>

<p>下面的示例仅用于学习目的。如果你想使用内置方法来扁平化数组,你可以考虑使用 {{jsxref("Array.prototype.flat()")}}(预计将成为 ES2019 的一部分,并且已在主要浏览器中实现)或参考其 polyfill。</p>

<pre class="brush: js">/**
 * Flattens passed array in one dimensional array
 *
 * @params {array} arr
 * @returns {array}
 */
function flatten(arr) {
  const result = [];

  arr.forEach((i) =&gt; {
    if (Array.isArray(i))
      result.push(...flatten(i));
    else
      result.push(i);
  })

  return result;
}

// Usage
const problem = [1, 2, 3, [4, 5, [6, 7], 8, 9]];

flatten(problem); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
</pre>

<h2 id="针对_promise_或_async_函数的使用备注">针对 promise 或 async 函数的使用备注</h2>

<p>如果使用 promise 或 async 函数作为 <code>forEach()</code> 等类似方法的 <code><var>callback</var></code> 参数,最好对造成的执行顺序影响多加考虑,否则容易出现错误。</p>

<pre class="brush: js">let ratings = [5, 4, 5];

let sum = 0;

let sumFunction = async function (a, b) {
    return a + b;
}

ratings.forEach(async function(rating) {
    sum = await sumFunction(sum, rating);
})

console.log(sum);
// Expected output: 14
// Actual output: 0
</pre>

<h2 id="Polyfill">Polyfill</h2>

<p><code>forEach()</code> 是在第五版本里被添加到 ECMA-262 标准的;这样它可能在标准的其他实现中不存在,你可以在你调用 <code>forEach()</code> 之前插入下面的代码,在本地不支持的情况下使用 <code>forEach()</code>。该算法是 ECMA-262 第5版中指定的算法。它假定 {{jsxref("Object")}} 和 {{jsxref("TypeError")}} 拥有它们的初始值,且 <code>callback.call</code> 等价于 {{jsxref("Function.prototype.call()")}}。</p>

<pre class="brush: js">// 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 &gt;&gt;&gt; 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 &gt; 1) {
      T = thisArg;
    }

    // 6. Let k be 0
    k = 0;

    // 7. Repeat, while k &lt; len
    while (k &lt; 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
  };
}
</pre>

<h2 id="规范">规范</h2>

<table class="standard-table">
 <thead>
  <tr>
   <th scope="col">规范</th>
   <th scope="col">状态</th>
   <th scope="col">备注</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-array.prototype.foreach', 'Array.prototype.forEach')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td></td>
  </tr>
  <tr>
   <td>{{SpecName('ES6', '#sec-array.prototype.foreach', 'Array.prototype.forEach')}}</td>
   <td>{{Spec2('ES6')}}</td>
   <td></td>
  </tr>
  <tr>
   <td>{{SpecName('ES5.1', '#sec-15.4.4.18', 'Array.prototype.forEach')}}</td>
   <td>{{Spec2('ES5.1')}}</td>
   <td>Initial definition. Implemented in JavaScript 1.6.</td>
  </tr>
 </tbody>
</table>

<h2 id="浏览器兼容性">浏览器兼容性</h2>

<div>


<p>{{Compat("javascript.builtins.Array.forEach")}}</p>
</div>

<h2 id="参见">参见</h2>

<ul>
 <li>{{jsxref("Array.prototype.find()")}}</li>
 <li>{{jsxref("Array.prototype.findIndex()")}}</li>
 <li>{{jsxref("Array.prototype.map()")}}</li>
 <li>{{jsxref("Array.prototype.filter()")}}</li>
 <li>{{jsxref("Array.prototype.every()")}}</li>
 <li>{{jsxref("Array.prototype.some()")}}</li>
 <li>{{jsxref("Map.prototype.forEach()")}}</li>
 <li>{{jsxref("Set.prototype.forEach()")}}</li>
</ul>