ToC
核心概念
函数组合,也叫饲养函数(compose)。为什么会叫饲养函数?可以理解为将其他的小的纯函数、偏函数、柯里化函数喂养给最后的一个大的功能函数,让这个功能变膘变壮,以完成最后的功能。举个例子:
1// 传统方式2function toUpperCase(str) {3 return str.toUpperCase()4}5
6function exclaim(str) {7 return str + '!'8}9
10// 传统调用方式5 collapsed lines
11console.log(exclaim(toUpperCase('hello'))) // HELLO!12
13// 使用 compose 的组合方式:14const composing = compose(exclaim, toUpperCasem) // 返回一个新的函数15composing('hello') // 调用组合好的函数集合
对比直接调用的方法,函数组合的好处是跟容易进行函数复用,而 compose
函数的定义如下:
1function compose(f, g) {2 return function(x) {3 return f(g(x))4 }5}
很简单的一个函数对不对,实际上核心的代码是第三行的 f(g(x))
,它通过自右向左组合函数并调用最后传入参数执行,得到最终的效果,这种组织代码的方式,被叫做 左倾
。简单来讲,左倾
就是将一个函数的执行放在另一个函数调用的 ()
中,将执行的函数返回值作为下一个执行函数的参数。以上 compose
函数虽然能满足需求,但是如果想要组合的函数再多一个的话,它就不得不进行修改了,所以这肯定不是最终方案。
改造函数
1function compose(...fns) {2 // 返回一个函数,并将接收到的函数传给最初传入的函数列表,函数列表会从右向左执行函数,最终返回最后一个函数的返回值3 return (value) => fns.reduceRight((params, fn) => fn(params), value)4}
我们再对这个函数传入更多函数进行测试:
1function toUpperCase(str) {2 return str.toUpperCase()3}4
5function exclaim(str) {6 return str + '!'7}8
9function split(str) {10 return str.split('')12 collapsed lines
11}12
13function reverse(arr) {14 return arr.reverse()15}16
17function join(arr) {18 return arr.join('')19}20
21const composing = compose(exclaim, toUpperCase, join, reverse, split)22console.log(composing('hello')) // OLLEH!
结合律(Associativity)
结合律在 JS 编程中同样是一个比较少见的概念,它与数学中的加法结合律概念一致
加法结合律:三个数相加,先把前面两个数相加,再加第三个数,或者先把后面两个数相加,再和第一个数相加,它们的和不变。
1const c1 = compose(join, reverse, split)('hello') // 'olleh'2const c2 = compose(compose(join, reverse), split)('hello') // 'olleh'3const c3 = compose(join, compose(reverse, split))('hello') // 'olleh'
结果如上,不管将他们的值怎么组合,只要函数传入的顺序不变,那么最终的结果也是不会变的。
Pointfree
Love means never having to say you’re sorry.
爱意味着永远不用说抱歉。
Pointfree style means never having to say your data.
而pointfree
意味着你永远不用主动表明你的数据。