本文正在参加「」
下午没事干刷牛客,然后看别人美团暑期一面问了个题:
实现一个 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)
大家可以拿这个去浏览器里跑,应当是能够跑通的。
我这个写的相当简易,并没有对 callbackfn 的类型做判断,没有包含 reduceRight 的情况,也可以看出来,reduce 的核心逻辑并没有我们想的那么复杂,其实就是一个for
循环能够解决的事情。
源码分析
我们来仔细分析一下源码,源码里面除了我刚刚的核心逻辑,还加了很多边缘 case 的判断
我们一个一个来分析:
第一个Case
aCallable
函数
- 判断传入的参数是否是函数
isCallable
-
documentAll
这个主要是为了判断是否对象存在。
tryToString
tryToString 这个函数仅仅是使用一个 try Catch,如果没有错误的话,用 String() 把参数转化为了 String 类型。
第二个Case
toObject
这个看起来就不难理解,主要是把 that,也就是数组里的 this 转化为 Object
-
requireObjectCoercible
这个函数主要是用来判断是否为 null/undefined,如果是就报错,否则就直接用 Object 一包裹进行转化。
-
-
isNullOrUndefined
-
判断是 null/undefined 的执行层
第三个Case
IndexedObject
这里我推导出来的逻辑应当永远直接走
$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
lengthOfArrayLike
这个 lengthOfArrayLike 函数主要是用来获取 this、也就是 Array 的长度的。
toLength
做最大长度的限制 2^53 - 1
-
toIntegerOrInfinity
获取具体的长度值~
-
-
- trunc
-
传入值,大于 0 放 floor,小于 0 放 ceil
第五个Case
第五个就很简单啦,有个东西叫reduceRight,我们想要从右往左遍历怎么办呢,所以我们引入一个 IS_RIGHT 这个参数来告诉 reduce 这玩意是不是从右边开始的
那么这就是这篇文章的全部内容啦~
点个赞再走吧~