aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/reference/global_objects/array/foreach
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
commit33058f2b292b3a581333bdfb21b8f671898c5060 (patch)
tree51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/javascript/reference/global_objects/array/foreach
parent8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff)
downloadtranslated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip
initial commit
Diffstat (limited to 'files/zh-cn/web/javascript/reference/global_objects/array/foreach')
-rw-r--r--files/zh-cn/web/javascript/reference/global_objects/array/foreach/index.html384
1 files changed, 384 insertions, 0 deletions
diff --git a/files/zh-cn/web/javascript/reference/global_objects/array/foreach/index.html b/files/zh-cn/web/javascript/reference/global_objects/array/foreach/index.html
new file mode 100644
index 0000000000..020a7dc3cd
--- /dev/null
+++ b/files/zh-cn/web/javascript/reference/global_objects/array/foreach/index.html
@@ -0,0 +1,384 @@
+---
+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>为数组中每个元素执行的函数,该函数接收一至三个参数:</dd>
+ <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="blockIndicator 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"><strong>注意:</strong>如果使用<a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭头函数表达式</a>来传入函数参数, <code><var>thisArg</var></code> 参数会被忽略,因为箭头函数在词法上绑定了 {{jsxref("Operators/this", "this")}} 值。</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>