试一试
const array = ["a", "b", "c"];
array.forEach((element) => console.log(element));
// Expected output: "a"
// Expected output: "b"
// Expected output: "c"
语法
forEach(callbackFn)
forEach(callbackFn, thisArg)
参数
callbackFn-
为数组中的每个元素执行一个函数。该函数的返回值将被忽略。该函数将使用以下参数进行调用:
thisArg可选-
在执行
callbackFn时用作this的值。请参阅 迭代方法。
返回值
无(undefined)。
描述
forEach() 方法是一个迭代方法。它会按升序索引顺序为数组中的每个元素调用一次提供的 callbackFn 函数。与 map() 不同,forEach() 始终返回 undefined 并且不可链式调用。典型的用例是在链式调用的末尾执行副作用。有关这些方法的一般工作原理,请阅读迭代方法部分。
callbackFn 仅对具有已赋值的数组索引调用。对于稀疏数组中的空槽,它不会被调用。
forEach() 方法是通用的。它只期望 this 值具有 length 属性和整数键属性。
除了抛出异常外,没有办法停止或中断 forEach() 循环。如果你需要这种行为,forEach() 方法就不是正确的工具。
可以使用诸如 for、for...of 和 for...in 之类的循环语句来实现提前终止。像 every()、some()、find() 和 findIndex() 这样的数组方法在不再需要进一步迭代时也会立即停止迭代。
forEach() 期望一个同步函数 — 它不会等待 Promise。在使用 Promise(或 async 函数)作为 forEach 回调时,请务必了解其含义。
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
要顺序或并发地运行一系列异步操作,请参阅Promise 组合。
示例
将 for 循环转换为 forEach
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);
});
打印数组内容
注意:为了在控制台中显示数组的内容,你可以使用 console.table(),它会打印数组的格式化版本。
以下示例说明了一种使用 forEach() 的替代方法。
以下代码会为数组中的每个元素打印一行
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
以下(人为的)示例会从数组中的每个条目更新对象属性
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
由于 forEach() 提供了 thisArg 参数(this),因此它在每次调用 callback 时都会被传递给它。回调函数将其用作其 this 值。
对象复制函数
以下代码会创建给定对象的副本。
创建对象副本的方法有多种。以下仅为一种方法,旨在解释 Array.prototype.forEach() 如何使用 Object.* 工具函数。
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
展平数组
以下示例仅用于学习目的。如果你想使用内置方法来展平数组,可以使用 Array.prototype.flat()。
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 的第三个参数
如果你想访问数组中的另一个元素,array 参数就很有用,尤其是在你没有引用数组的现有变量时。以下示例首先使用 filter() 提取正数,然后使用 forEach() 打印其邻居。
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()
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 的缺失值,回调函数不会被调用。
在非数组对象上调用 forEach()
forEach() 方法读取 this 的 length 属性,然后访问键为小于 length 的非负整数的每个属性。
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
规范
| 规范 |
|---|
| ECMAScript® 2026 语言规范 # sec-array.prototype.foreach |
浏览器兼容性
加载中…