前言
写这篇文章的目的是让我更好的理解它,我很早就看过compose的实现,但时不时得忘记,特别的是 reducer下的实现,那肯定应该是我理解有问题,今天看ssh大佬的群里也有讨论;决定重新再理解一遍,有了自己的想法,赶脚写一下。(有不对的地方,请多多指点)
compose实现了什么
(...args) => f1(f2(f3(f4(...arg)))) // 1 -> n思考一下compose的雏形
(...args) => f1(f2(...args)) //我觉得是这样的, 😄👆这个🌰实现了的是一个函数,入参是...args,执行了f1函数,入参是f2(...args)
(记住上面句话哦!!!)
发现这个函数模型的前生
这位大佬心路历程应该是这样的(纯属虚构)
有一天大佬,想实现一个函数,入参是...args,执行了f1函数,入参是f2(...args)
(...args) => f1(f2(...args))想再加个f3, 试试?
(...args) => f1(f2(f3(...args)))心想有点意思😯,再来一个
(...args) => f1(f2(f3(f4(...args))))他开始想是n个函数怎么搞呢,难啊😣
是不是有规律呢?
(...args) => f1(f2(...args))
(...args) => f1(f2(f3(...args)))
(...args) => f1(f2(f3(f4(...args))))
(...args) => f1(f2(f3(f4(f5(...args))))))聪明的大佬🧍♂️发现
(...args) => f1(f2(f3(...args)))这个是不是可以这样理解
实现了一个函数入参是...args,执行了_f函数入参是f3(...args)
那_f是什么呢?应该是个函数,而且内部执行了f1(f2()),这...不是他嘛😄
(...args) => f1(f2(...args))那下面是不是也这样呢?
(...args) => f1(f2(f3(f4(...args)))) //(...args) => _f(f4(...args))
(...args) => f1(f2(f3(...args))) //_f函数 哇好神奇啊
不就这样嘛,🍳
let cache = (...args) => f1(f2(...args))
cache = (...args) => cache(f3(...args))完整实现一下
按照自己思路,笨笨的实现一下😄
let cache;
function compose(...fns) {
let ff = fns[0]
for (let i = 1; i < fns.length; i ++) {
if (cache) {
cache = (...args) => cache(fns[i](...args));
} else {
cache = (...args) => ff(fns[i](...args));
}
}
return cache;
}大神的实现
const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));再来理解一下,仔细一看,这个f不是就是我上面的cache嘛,大佬就是不一样,实现得如此优雅
回顾一下reduce的实现吧
//简化版 仅供参考
Array.prototype.myReduce = function (fn, p) {
let that = this;
p = p || that[0];
for (let i = 1; i < that.length; i++) {
p = fn(p, that[i]);
}
return p;
}总结
一些高阶函数,感觉都是由简到繁的抽象,代码的重构亦是如此
这个理解方式对我蛮好理解的,希望对你帮助