js函数式编程-函数合成和柯里化
函数式编程有2个最基本的运算:合成(compose)和柯里化(currying)
合成:如果一个值要经过多个函数才能编程另一个值,那么我们可以把中间的步骤合并成一个函数,这个叫做函数的合成
函数的合成我们采用es6的reduce方法,先举一个小例子说明reduce的特性
const arr = [1,2,3,4] let a = arr.reduce(function(total,next){ return total+next }) console.log(a) //10
可以看到,reduce接收一个函数,函数的两个参数分别代表了累加返回值和下一个要处理的值,我们用reduce最多的场景是用它来求和。那么如果我们把arr数组换成函数数组,在reduce里一层一层的执行函数不就可以实现函数的合成了嘛。
下面我们把上边的数字组成的数组换成函数组成的数组,再用一个函数包装一下reduce函数
function f1(arg){ console.log("f1",arg) return arg; } function f2(arg){ console.log("f2",arg) return arg; } function f3(arg){ console.log("f3",arg) return arg; } 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))) return funcs.reduce(function(a,b){ return function(o){ return a(b(o)) } }) } let res = compose(f1,f2,f3)("omg");//f1(f2(f3("omg"))) 洋葱模型 console.log("res",res);
打印结果:
f3 omg
f2 omg
f1 omg
res omg
可以看到上面的compose函数接收了一个函数数组,函数里面reduce的部分有点绕,我们逐步讲解一下,首先,compose函数需要返回一个reduce函数处理过的值,reduce函数接收一个函数作为参数,这个函数的第一个参数a就相当于上面累加例子里的total,b就相当于下一个要执行的函数。到这里其实就结束了,但是我们将来还需要给函数传递参数,比如传入了一个omg字符串,那么我们希望compose函数返回值也是一个函数,我们才能在调用的时候再传递参数。所以我们在里面再套一层函数来接收参数o。
上面的compose最终的目的是实现了一个像洋葱的函数调用形式,一层包着一层 f1(f2(f3("omg")))
柯里化:把接收多个参数的函数变成接收一个参数的函数,并且返回接收余下参数而且返回结果的新函数
举个例子说明一下柯里化后的函数和之前的有什么不同
// curry之前 function add(x,y){ return x+y } add(1,2) // curry之后 function newAdd(x){ return function(y){ return x+y } } let aa = newAdd(1)(2) console.log(aa)
可以看到函数的柯里化就是利用闭包的特性,记住参数,然后返回一个函数,函数的返回值是最终的结果,经过柯里化的函数我们的调用会更加灵活
那么有小伙伴问了,这个函数究竟灵活在哪里了呀?
我感觉主要是柯里化提高了函数的适用性,我们可以想用什么功能就传递什么参数,根据传入参数的数量实现函数的随取随用。增加了代码的复用性。
更多函数式编程知识参见:https://llh911001.gitbooks.io/mostly-adequate-guide-chinese/content/ch1.html#%E4%BB%8B%E7%BB%8D