跳至主要內容

forEach 原理

wzCoding大约 2 分钟综合知识forEach 原理

forEach 原理

forEach() 方法是我们在处理数组使经常用到的遍历方法,它相较于其他循环方法可以使代码更加简洁,下面会探究 forEach() 方法的实现原理。

实现原理

ECMA (262) 标准中关于 forEach() 的实现步骤如下:

When the forEach method is called, the following steps are taken:

  1. Let O be ? ToObject(this value).
  2. Let len be ? LengthOfArrayLike(O).
  3. If IsCallable(callbackfn) is false, throw a TypeError exception.
  4. Let k be 0.
  5. 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.
  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]