reduce实现compose和中间件
函数的深度嵌套调用
通常当下一个调用的函数需要使用到上一个函数执行结果的时候,我们一般会这么做:
例如 吃一次饭:
// 买食物
function buyFood(moeny) {
return 'original food'
}
// 处理食材
function dealFood(originalFood) {
return 'ingredients'
}
// 烹饪
function cookFood(ingredients) {
return 'food'
}
// 吃
function eat(food){}我们大约需要经历这些步骤,那么一次午饭我们这样:eat(cookFood(dealFood(buyFood(moeny)))),吃一次晚饭:eat(cookFood(dealFood(buyFood(moeny))))...
这种方式不仅增大代码量,更增加阅读和维护的难度;如果业务突然有了改动:一家人吃饭,你怎么能做好了自己就开吃,你得喊家人一起吃对吧?
那么烹饪和吃之间我们需要加一个:
// 喊家人吃饭
function callFamily(ingredients){
return 'Family'
}更好得方式肯定是整合封装一下:
function eatMeal(money){
return eat(cookFood(dealFood(buyFood(moeny))))
}这样调用的时候,也只需要eatMeal(money),需要callFamily也能直接修改eatMeal即可。但是这样,如果更多的嵌套,就有更多的层叠关系。而我们希望通过类似这样的关系来描述:step1 => step2 => step3 ..
通过reduce实现compose
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)我们需要的结果类似这样:
[step1,step2,step3,step4 ... ].reduce(function(arg,fn){
return fn(arg)
},arg)传入一个参数arg,顺序执行数组中的函数,并且后续每一次的入参都是上一步的结果,执行完毕后返回结果。
封装一下:
function compose(fns, arg) {
Array.prototype.reduce.call(fns, (pre, cur) => {
return cur(pre)
}, arg)
}
compose([step1,step2,step3],arg)但是和第一次问题一样,每一次调用都必须带上所有步骤,不利于编码和维护。
我们需要的是一次定义,多次调用时候只传入参数:
function compose() {
var fns = arguments;
return function (arg) {
return Array.prototype.reduce.call(fns, (pre, cur) => {
return cur(pre)
}, arg)
}
}
function add(num) {
var result = num + 1;
console.log(result)
return result;
}
var add3Times = compose(add, add, add)
console.log(add3Times(2))再对比网上流传的compose:
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}多了两个判断:判断没有传入的函数和传入一个函数的时候处理,并且和上面的实现不同,reduce每一步返回的并不是上一步的结果,而是一个函数,最后一样返回一个函数。
第一种情况返回的函数中,函数体内包括reduce的执行,所以后续每次调用都需要重新reduce然后返回结果,并且因为占用arguments,所以compose的执行栈也会一直存在内存中;而第二种返回的是已经经过reduce组装之后的函数,不再占用,所以原来的执行栈可以释放。
修改一下:
function compose() {
var fns = arguments;
return Array.prototype.reduce.call(fns, (pre, cur) => {
return (arg) => {
return cur(pre(arg))
}
})
}中间件
中间件就是一个函数,可以通过中间件组合成一个最终你想要的逻辑函数。
