forEach 原理
大约 2 分钟
forEach 原理
forEach()
方法是我们在处理数组使经常用到的遍历方法,它相较于其他循环方法可以使代码更加简洁,下面会探究 forEach()
方法的实现原理。
实现原理
ECMA (262) 标准中关于 forEach()
的实现步骤如下:
When the forEach method is called, the following steps are taken:
- Let O be ? ToObject(this value).
- Let len be ? LengthOfArrayLike(O).
- If IsCallable(callbackfn) is false, throw a TypeError exception.
- Let k be 0.
- Repeat, while k < len,
- Let Pk be ! ToString(𝔽(k)).
- Let kPresent be ? HasProperty(O, Pk).
- If kPresent is true, then
- Let kValue be ? Get(O, Pk).
- Perform ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »).
- Set k to k + 1.
- Return undefined.
具体实现
上面引用的一系列步骤详细说明了 forEach()
的实现标准,下面按照这个标准来实现一个 forEach()
方法。
具体实现代码如下:
Array.prototype.myForEach = function(callback){
//第一步,获取 this 上下文,并将之转换为对象,这里由于 this 已经是对象了,所以跳过这个步骤
//第二步,获取并保存数组的长度
let len = this.length
//第三步,判断传入的回调函数是否是 function 类型,不是则抛出错误
if(typeof callback !== 'function'){
throw new TypeError(`${callback.name} is not a function`)
}
//第四步,设置一个循环变量 k,初始值为 0
let k = 0
//第五步,使用 while 循环,循环条件为 k < len(数组长度)
while( k < len ){
//将 k 转换为字符串类型,用 pk 保存
let Pk = String(k)
//这一步将数组看作对象,判断 Pk(数组索引)是否存在
let kPresent = this.hasOwnProperty(Pk)
//这一步判断如果 kPresent 存在,则继续执行
if(kPresent){
// 获取 Pk 索引对应的值
let kValue = this[Pk]
// 调用传入的回调方法,并传入数组当前项,数组当前索引,数组本身 参数
callback.call(this, kValue, k, this)
}
// 循环变量增加
k++
}
//第六步,返回 undefined
return undefined
}
// 使用
const arr = [1,2,3,4,5]
arr.myForEach((item,index,self)=>{
console.log(item)
console.log(index)
console.log(self)
})
// 输出:
//1
// 0
// (5) [1, 2, 3, 4, 5]
// 2
// 1
// (5) [1, 2, 3, 4, 5]
// 3
// 2
// (5) [1, 2, 3, 4, 5]
// 4
// 3
// (5) [1, 2, 3, 4, 5]
// 5
// 4
// (5) [1, 2, 3, 4, 5]