compose 是函数式编程中一个非常重要的函数,compose的函数作用就是组合函数,将多个函数串联起来,上一个函数的输出作为下一个函数的输入。
效果如下:
function f1(x){
return x+10;
}
function f2(x){
return x*10;
}
function f3(x){
return x-10;
}
let cal = compose(f1,f2,f3);
console.log(cal(5)));// compose的累加顺序是从右往左,结果为:((5-10)*10)+10 = -40
那么如何实现呢?
最直接的想法:
let cal = f1(f2(f3(5)));
console.log(cal);//-40
或者说,我们再优化一下,将函数作为参数传进来,并返回一个匿名函数:
let compose1 = function(f1,f2,f3){
return function(x){
return f1(f2(f3(x)));
}
}
let cal1 = compose1(f1,f2,f3);
console.log(cal1(5));//-40
但是核心问题没有解决,如何将 return f1(f2(f3(x))) 进行 “扁平化” ?
为了解决此问题,我们先熟悉js的reduce函数:
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
reduceRight() 方法的功能和 reduce() 功能是一样的,不同的是 reduceRight() 从数组的末尾向前将数组中的数组项做累加。
因为compose函数的定义是从末尾累加,所以我们选用reduceRight方法:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
参数 | 描述 |
function(total,currentValue, index, arr) | 必需。用于执行每个数组元素的函数。 函数参数: |
initialValue | 可选。传递给函数的初始值 |
参数 | 描述 |
total | 必需。初始值, 或者计算结束后的返回值。 |
currentValue | 必需。当前元素 |
currentIndex | 可选。当前元素的索引 |
arr | 可选。当前元素所属的数组对象。 |
reduceRight的例子:
var nums = [2,3,5,4];
function getSum(total,x){
//LOOP1:total+x = 14
//LOOP2:total+x = 19
//LOOP3:total+x = 22
//LOOP4:total+x = 24
return total+x;
}
console.log(nums.reduceRight(getSum,10));//24
下面,我们利用reduceRight将compose1进行改进:
let compose2 = function(){
let args = [].slice.call(arguments);
//[ [Function: f1], [Function: f2], [Function: f3] ]
return function(x){
//x=5
return args.reduceRight(function(res,cb){
//LOOP1:cb = [Function: f3] res = 5
//LOOP2:cb = [Function: f2] res = -5
//LOOP3:cb = [Function: f1] res = -50
return cb(res);
//LOOP1:cb(res) = -5;
//LOOP2:cb(res) = -50;
//LOOP3:cb(res) = -40;
} , x)
//return -40
}
}
let cal2 = compose2(f1,f2,f3);
console.log(cal2(5));//-40
对应的ES6写法:
const compose3= (...args) => x =>args.reduceRight((res,cb) => cb(res),x);
let cal3 = compose3(f1,f2,f3);
console.log(cal3(5));//-40