1.前言
compose的源码较少,但是里面却有很多值得我们学习的地方,首先先介绍下数组的方法之一reduce。 这里先贴几个链接关于reduce的。这俩篇对我下面提到的initialValue是否提供有着很详细的描述。
2.Reduce
a.用法:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
b.参数介绍
total:累加器值
currentValue:数组遍历时当前值
currentIndex:数组遍历时当前索引
arr:当前遍历的数组
initialValue:作为累加器的初始值,这里需要注意的是,如果不赋该值的话,那么total的初始值就是arr[0]
c.说明
reduce执行时对数组中每一项元素执行传入的callback,参数分别为total, currentValue, currentIndex, arr。 当第一次执行时,如果initialValue提供的话,那么total=initialValue,并且从数组的第1位元素开始遍历。 如果initialValue没有提供的话,那么total=arr[0],并且从数组的第2位元素开始遍历。
注:每次遍历处理后需要return new total作为下一次遍历的total值
d.实例
(1)数组之和
arr.reduce((total, currentValue) => { return total + currentValue }, 0)
等价于arr.reduce((total, currentValue) => { return total + currentValue })(不传initialValue)
(2)反转对象的键值对key和value(最近项目里自己用的^-^)
obj = { a: 1, b: 2, c: 3 }
Object.keys(obj).reduce((total, currentValue) => {
total[obj[currentValue]] = currentValue;
return total;
}, {})

其他有很多用法,自己在实践中多使用吧。
3.Compose
重点来了,Compose就是用reduce来实现的。

compose(f,g) -> (..args) => f(g(...args))
compose(f,g,h) -> (..args) => f(g(h(...args)))
compose主要用在redux中间件,applyMiddleware函数用到compose,applyMiddleware后面我再说。
首先我们看compose(f,g),前面说到initialValue没有提供的话,那么funcs.reduce((a, b) => (...args) => a(b(...args)))
第一次遍历的时候a=f, b=g, 返回的就是函数(...args) => f(g(...args)).
然后我们再看compose(f,g,h),为了便于区分,第一次返回的结果我们令 k = (...arr) => f(g(...arr))
第二次遍历则为(k,h) => (...args) => k(h(...args)),这里...arr 就是h(...args),然后替换进来。就成了f(g(h(...args)))。
一开始我也不是很理解这里,琢磨了好一会才明白。主要就是我上面提到不传initialValue的话,total=arr[0], currentValue=arr[1]。理解了这个地方,你就会对reduce的使用更加熟练,原先我也不怎么使用这个函数,其实还是很好用的。
4.总结
学习的过程中多思考,多看源码还是有好处的。对一个问题不了解,那么就拆开几个部分,一个一个去理解,那么问题自然就解开了。