export default 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)))
}
复制代码
须要说明的是,compose
函数的存在实际上是服务于中间件的,即当咱们使用applyMiddleware
实现功能加强的背后,其实就是利用了compose
函数将这多个加强函数进行合理的组合。javascript
首先,compose
函数利用了es6的rest参数,将多个类型为函数的参数收集到一个叫做funcs
的数组中,而后进行进一步逻辑判断,最终结果都会是返回一个函数,保证输入输出。java
来用例子说话吧:es6
// 初始数据
let data = 1;
// 加1函数
const add1 = v => v + 1;
// 乘2函数
const multi2 = v => v * 2;
// 1. compose没有参数
const func1 = compose();
func1(data); // -> 1
// 2. compose有一个参数,为add1
const func2 = compose(add1);
func2(data); // -> 2,运算顺序为 1 + 1
// 3. compose有两个参数,顺序依次为add1与multi2
const func3 = compose(add1, multi2);
func3(data); // -> 3,运算顺序为 1 * 2 + 1
// 4. compose有两个参数,顺序依次为multi2与add1
const func4 = compose(multi2, add1);
func4(data); // -> 4,运算顺序为 (1 + 1) * 2
复制代码
这里重点关注一下func3
与func4
能够看出,接受参数相同可是顺序不一样,也会致使结果的不一样,很明显,越是在后面的函数,执行的次序越靠前,从源码中的a(b(...args))
也能够获得印证。redux
以上其实就是redux中间件的基本实现原理,关于中间件,咱们后续再说。数组
聊完了compose
这个组合函数,顺便来聊一下柯里化
这个概念吧,由于这个概念在你编写本身的中间件的时候可能会涉及到,下面是来自于百度百科的解释:app
在计算机科学中,柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,而且返回接受余下的参数且返回结果的新函数的技术。函数
若是须要举例,那么也很简单,就像这样子:post
// 如今有个add函数接受两个参数a、b,并返回a + b
const add = (a, b) => a + b;
add(1, 2); // -> 3
// 如今用柯里化的思想来实现一下
const addByCurrying = a => b => a + b;
addByCurrying(1)(2); // -> 3
复制代码
能够看到其实使用柯里化就是将本来接受多个参数的函数变为一次只接受一个参数,并返回一个新的函数用来处理剩余的函数,就像是add
改写为addByCurrying
后,实现一个a+b
实际上是利用了两个函数调用完成的,第一次接受1,第二次接受2。spa
讲完了柯里化的含义,那么为何要费劲套这么多层去实现一个a+b?那确定是有他的好处的,想了解具体的就移步这里——详解JS函数柯里化,感受这篇文章中写的很清楚了。rest