Array.prototype.forEach ( callbackfn [ , thisArg ] )
callbackfn should be a function that accepts three arguments. forEach calls callbackfn once for each element present in the array, in ascending order. callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array. callbackfn 应该是一个接受三个参数的函数。forEach 会按升序为数组中每个存在的元素调用一次 callbackfn。callbackfn 只针对数组中实际存在的元素被调用;对于数组中缺失的元素,不会调用 callbackfn。
If a thisArg parameter is provided, it will be used as the this value for each invocation of callbackfn. If it is not provided, undefined is used instead. 如果提供了 thisArg 参数,它将被用作每次调用 callbackfn 时的 this 值。如果没有提供,将使用 undefined 作为 this 值。
callbackfn is called with three arguments: the value of the element, the index of the element, and the object being traversed. callbackfn 被调用时会传入三个参数:元素的值、元素的索引以及正在遍历的对象。
forEach does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn. forEach 不会直接改变调用它的对象,但对象可能会因调用 callbackfn 而被改变。
The forEach function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method. forEach 函数是有意设计为通用的;它不要求其 this 值必须是一个数组对象。因此,它可以被转移到其他类型的对象上,用作方法。
const arr1 = [1, 2, 3];
arr1.forEach((item) => {
console.log("push console: " + item);
arr1.push(item + 3);
});
// push console: 1
// push console: 2
// push console: 3
这里对应着3,也就是运行前就已经确定了长度;即使在push也不会循环到新增的item。
const arr2 = [1, 2, 3];
arr2.forEach((item) => {
console.log("pop console: " + item);
arr2.pop();
});
// pop console: 1
// pop console: 2
这里对应着8.b,每次循环的时候先检查,在执行;
// 向数组原型添加自定义的 myForEach 方法
Array.prototype.myForEach = function (callback, thisArg) {
// 步骤1:尝试将 this 转换为对象
let O;
try {
O = Object(this);
} catch (error) {
throw new TypeError("Cannot convert undefined or null to object");
}
// 步骤3:尝试获取对象的长度
let len;
try {
len = O.length >>> 0; // 使用无符号右移保证长度为数字且为非负整数
} catch (error) {
throw new TypeError("Cannot get length property of object");
}
// 步骤5:检查回调函数是否可调用
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}
// 步骤6:处理 thisArg,如果未提供,则默认为 undefined
let T = thisArg;
// 步骤7:初始化索引 k
let k = 0;
// 步骤8:遍历数组
while (k < len) {
let kValue, kPresent;
try {
// 步骤8a: 生成属性名 Pk
let Pk = k.toString();
// 步骤8b: 检查属性 Pk 是否在对象 O 上
kPresent = O.hasOwnProperty(Pk);
if (kPresent) {
// 步骤8d(i): 获取 Pk 对应的值
kValue = O[Pk];
// 步骤8d(iii): 调用回调函数
callback.call(T, kValue, k, O);
}
} catch (error) {
// 处理获取属性或调用回调时的异常
throw error;
}
// 步骤8e: 增加 k 的值
k++;
}
// 步骤9:返回 undefined
return undefined;
};