从 core-js 一起实现一个简单版本的 reduce

lxf2023-04-14 09:10:02

本文正在参加「」

下午没事干刷牛客,然后看别人美团暑期一面问了个题:

实现一个 Array.reduce

我当时就惊了,发现自己除了用过,还真不知道这玩意咋写的。

然后我就去扒了一下 core-js 的源码,看了之后觉得不过如此(手动 doge

后面的文章节奏呢大概是:我先写一个简单版本出来,然后再分析分析源码。

那么话不多说,就此开始啦。

简单版本

我自己尝试写了一个简单

Array.prototype.reduce = function(callbackfn,  initialValue) {
  // 源码中这里有很多边缘 case 的处理
  const self = this
  const length = self.length
  let memo = initialValue
  for(let index = 0; length > index; index += 1) if (index in self){
    memo = callbackfn(memo, self[index], index, 0)
  }
  return memo
}
const arr = [1, 2, 3, 4, 5]
arr.reduce((prev, cur) => prev + cur, 0)

从 core-js 一起实现一个简单版本的 reduce

大家可以拿这个去浏览器里跑,应当是能够跑通的。

我这个写的相当简易,并没有对 callbackfn 的类型做判断,没有包含 reduceRight 的情况,也可以看出来,reduce 的核心逻辑并没有我们想的那么复杂,其实就是一个for循环能够解决的事情。

源码分析

我们来仔细分析一下源码,源码里面除了我刚刚的核心逻辑,还加了很多边缘 case 的判断

从 core-js 一起实现一个简单版本的 reduce

我们一个一个来分析:

第一个Case

  1. aCallable 函数
  • 判断传入的参数是否是函数

从 core-js 一起实现一个简单版本的 reduce

  • isCallable

从 core-js 一起实现一个简单版本的 reduce

    • documentAll

从 core-js 一起实现一个简单版本的 reduce

这个主要是为了判断是否对象存在。

  • tryToString

tryToString 这个函数仅仅是使用一个 try Catch,如果没有错误的话,用 String() 把参数转化为了 String 类型。

第二个Case

  1. toObject

这个看起来就不难理解,主要是把 that,也就是数组里的 this 转化为 Object

从 core-js 一起实现一个简单版本的 reduce

    • requireObjectCoercible

这个函数主要是用来判断是否为 null/undefined,如果是就报错,否则就直接用 Object 一包裹进行转化。

从 core-js 一起实现一个简单版本的 reduce

      • isNullOrUndefined

判断是 null/undefined 的执行层

从 core-js 一起实现一个简单版本的 reduce

第三个Case

  1. IndexedObject

从 core-js 一起实现一个简单版本的 reduce

这里我推导出来的逻辑应当永远直接走 $Object 要是有懂哥可以教一下,确实没看明白,

// fails
module.exports = function (exec) {
  try {
    return !!exec();
  } catch (error) {
    return true;
  }
};
// classof 里面写的嵌套太多了,其实就是
Array.prototype.slice(8, -1).call(obj)

我理解应该是对 String 的类型做一个判断,如果是 String 我们就 split 成一个数组,一样可以 reduce。

第四个Case

  1. lengthOfArrayLike

这个 lengthOfArrayLike 函数主要是用来获取 this、也就是 Array 的长度的。

从 core-js 一起实现一个简单版本的 reduce

  • toLength

做最大长度的限制 2^53 - 1

从 core-js 一起实现一个简单版本的 reduce

    • toIntegerOrInfinity

从 core-js 一起实现一个简单版本的 reduce

获取具体的长度值~

      • trunc

传入值,大于 0 放 floor,小于 0 放 ceil

从 core-js 一起实现一个简单版本的 reduce

第五个Case

第五个就很简单啦,有个东西叫reduceRight,我们想要从右往左遍历怎么办呢,所以我们引入一个 IS_RIGHT 这个参数来告诉 reduce 这玩意是不是从右边开始的

从 core-js 一起实现一个简单版本的 reduce

那么这就是这篇文章的全部内容啦~

点个赞再走吧~