Array.prototype.forEach()

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

¥The forEach() method of Array instances executes a provided function once for each array element.

Try it

语法

¥Syntax

js
forEach(callbackFn)
forEach(callbackFn, thisArg)

参数

¥Parameters

callbackFn

对数组中的每个元素执行的函数。它的返回值被丢弃。使用以下参数调用该函数:

element

数组中当前正在处理的元素。

index

数组中当前正在处理的元素的索引。

array

调用了数组 forEach()

thisArg Optional

执行 callbackFn 时用作 this 的值。参见 迭代法

返回值

¥Return value

无 (undefined)。

¥None (undefined).

描述

¥Description

forEach() 方法是 迭代法 方法。它按索引升序为数组中的每个元素调用一次提供的 callbackFn 函数。与 map() 不同,forEach() 始终返回 undefined 并且不可链接。典型的用例是在链的末尾执行副作用。请阅读 迭代法 部分,了解有关这些方法一般如何工作的更多信息。

¥The forEach() method is an iterative method. It calls a provided callbackFn function once for each element in an array in ascending-index order. Unlike map(), forEach() always returns undefined and is not chainable. The typical use case is to execute side effects at the end of a chain. Read the iterative methods section for more information about how these methods work in general.

callbackFn 仅针对已赋值的数组索引调用。稀疏数组 中的空槽不会调用它。

¥callbackFn is invoked only for array indexes which have assigned values. It is not invoked for empty slots in sparse arrays.

forEach() 方法是 generic。它只期望 this 值具有 length 属性和整数键控属性。

¥The forEach() method is generic. It only expects the this value to have a length property and integer-keyed properties.

除了抛出异常之外,没有其他方法可以停止或中断 forEach() 循环。如果你需要这样的行为,那么 forEach() 方法是错误的工具。

¥There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.

提前终止可以通过诸如 forfor...offor...in 之类的循环语句来完成。当不需要进一步迭代时,像 every()some()find()findIndex() 这样的数组方法也会立即停止迭代。

¥Early termination may be accomplished with looping statements like for, for...of, and for...in. Array methods like every(), some(), find(), and findIndex() also stops iteration immediately when further iteration is not necessary.

forEach() 期望一个同步函数 - 它不等待承诺。确保你了解使用 Promise(或异步函数)作为 forEach 回调时的含义。

¥forEach() expects a synchronous function — it does not wait for promises. Make sure you are aware of the implications while using promises (or async functions) as forEach callbacks.

js
const ratings = [5, 4, 5];
let sum = 0;

const sumFunction = async (a, b) => a + b;

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

console.log(sum);
// Naively expected output: 14
// Actual output: 0

要顺序或同时运行一系列异步操作,请参阅 承诺作文

¥To run a series of asynchronous operations sequentially or concurrently, see promise composition.

示例

¥Examples

将 for 循环转换为 forEach

¥Converting a for loop to forEach

js
const items = ["item1", "item2", "item3"];
const copyItems = [];

// before
for (let i = 0; i < items.length; i++) {
  copyItems.push(items[i]);
}

// after
items.forEach((item) => {
  copyItems.push(item);
});

打印数组的内容

¥Printing the contents of an array

注意:为了在控制台中显示数组的内容,你可以使用 console.table(),它会打印数组的格式化版本。

¥Note: In order to display the content of an array in the console, you can use console.table(), which prints a formatted version of the array.

以下示例说明了使用 forEach() 的替代方法。

¥The following example illustrates an alternative approach, using forEach().

以下代码为数组中的每个元素记录一行:

¥The following code logs a line for each element in an array:

js
const 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

¥Using thisArg

以下(人为的)示例从数组中的每个条目更新对象的属性:

¥The following (contrived) example updates an object's properties from each entry in the array:

js
class Counter {
  constructor() {
    this.sum = 0;
    this.count = 0;
  }
  add(array) {
    // Only function expressions have their own this bindings.
    array.forEach(function countEntry(entry) {
      this.sum += entry;
      ++this.count;
    }, this);
  }
}

const obj = new Counter();
obj.add([2, 5, 9]);
console.log(obj.count); // 3
console.log(obj.sum); // 16

由于 thisArg 参数 (this) 被提供给 forEach(),因此每次调用时都会将其传递给 callback。回调使用它作为 this 值。

¥Since the thisArg parameter (this) is provided to forEach(), it is passed to callback each time it's invoked. The callback uses it as its this value.

注意:如果使用 箭头函数表达式 传递回调函数,则可以省略 thisArg 参数,因为所有箭头函数都在词法上绑定 this 值。

¥Note: If passing the callback function used an arrow function expression, the thisArg parameter could be omitted, since all arrow functions lexically bind the this value.

对象复制功能

¥An object copy function

以下代码创建给定对象的副本。

¥The following code creates a copy of a given object.

创建对象的副本有多种方法。下面只是一种方法,旨在解释 Array.prototype.forEach() 如何通过使用 Object.* 实用函数来工作。

¥There are different ways to create a copy of an object. The following is just one way and is presented to explain how Array.prototype.forEach() works by using Object.* utility functions.

js
const copy = (obj) => {
  const copy = Object.create(Object.getPrototypeOf(obj));
  const propNames = Object.getOwnPropertyNames(obj);
  propNames.forEach((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 looks like obj1 now

展平数组

¥Flatten an array

以下示例仅用于学习目的。如果你想使用内置方法展平数组,可以使用 Array.prototype.flat()

¥The following example is only here for learning purpose. If you want to flatten an array using built-in methods, you can use Array.prototype.flat().

js
const flatten = (arr) => {
  const result = [];
  arr.forEach((item) => {
    if (Array.isArray(item)) {
      result.push(...flatten(item));
    } else {
      result.push(item);
    }
  });
  return result;
};

// Usage
const nested = [1, 2, 3, [4, 5, [6, 7], 8, 9]];
console.log(flatten(nested)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]

使用 callbackFn 的第三个参数

¥Using the third argument of callbackFn

如果你想访问数组中的另一个元素,特别是当你没有引用该数组的现有变量时,array 参数非常有用。以下示例首先使用 filter() 提取正值,然后使用 forEach() 记录其邻居。

¥The array argument is useful if you want to access another element in the array, especially when you don't have an existing variable that refers to the array. The following example first uses filter() to extract the positive values and then uses forEach() to log its neighbors.

js
const numbers = [3, -1, 1, 4, 1, 5];
numbers
  .filter((num) => num > 0)
  .forEach((num, idx, arr) => {
    // Without the arr argument, there's no way to easily access the
    // intermediate array without saving it to a variable.
    console.log(arr[idx - 1], num, arr[idx + 1]);
  });
// undefined 3 1
// 3 1 4
// 1 4 1
// 4 1 5
// 1 5 undefined

在稀疏数组上使用 forEach()

¥Using forEach() on sparse arrays

js
const arraySparse = [1, 3, /* empty */, 7];
let numCallbackRuns = 0;

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

console.log({ numCallbackRuns });

// { element: 1 }
// { element: 3 }
// { element: 7 }
// { numCallbackRuns: 3 }

对于索引 2 处的缺失值,不会调用回调函数。

¥The callback function is not invoked for the missing value at index 2.

对非数组对象调用 forEach()

¥Calling forEach() on non-array objects

forEach() 方法读取 thislength 属性,然后访问键为小于 length 的非负整数的每个属性。

¥The forEach() method reads the length property of this and then accesses each property whose key is a nonnegative integer less than length.

js
const arrayLike = {
  length: 3,
  0: 2,
  1: 3,
  2: 4,
  3: 5, // ignored by forEach() since length is 3
};
Array.prototype.forEach.call(arrayLike, (x) => console.log(x));
// 2
// 3
// 4

规范

Specification
ECMAScript Language Specification
# sec-array.prototype.foreach

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看