函数柯里化currying,是函数式编程很是重要的一个标志。它的实现须要知足如下条件,首先就是函数能够做为参数进行传递,而后就是函数能够做为返回值return出去。咱们依靠这个特性编写不少优雅酷炫的代码。那咱们来看一下最简单的实现。编程
你们通常都是举addSum的例子,我固然也不例外。数组
add = (num1)-> return (num2)-> return num1 + num2; add3 = add(3); add5 = add(5); add3(5) # 返回8 add5(5) # 返回10
上述例子其实已经对柯里化的实现,有一个很是好的了解了。其实也就是“分步求值”,咱们能够把第一个参数经过闭包保存起来,以供return出去的匿名函数使用。因此咱们能够根据add来自定义各类各样的新函数。闭包
咱们要使某个函数能够柯里化,难道必定要在函数建立时,就具备柯里化的特性么?假设咱们的add函数,起初并不具备柯里化特性的,咱们须要怎么作才能让它柯里化呢?app
add = (num1, num2)-> return num1 + num2; curry = (fn)-> args = [].slice.call(arguments, 1); return ()-> [].push.apply(args, arguments); return fn.apply(this, args); add5 = curry(add, 5) add5(3) # 返回8
原理仍是同样的,咱们经过curry函数,让fn须要的第一次的参数经过闭包保存在args的变量里,以供匿名函数使用。最后结合第二次须要的参数,使用apply一次性导入args,完成操做。函数式编程
上述咱们看到的都是分两步求值,这其实并不符合咱们更丰富的实际需求。咱们须要考虑如何才能够将函数柯里化变成咱们须要的想分步便分步,想中止便中止呢?函数
首先咱们须要约定一个规则,这个规则和大部分的Getter/Setter方法同样。当函数没有参数时,执行的是Getter,而有参数的话,则是执行“Setter”。(这个也是Javascript实现简陋的函数重载的一种方法)this
curry = (fn)-> args = []; return ()-> if arguments.length == 0 return fn.apply(this, args); else [].push.apply(args, arguments); return arguments.callee; addSum = ()-> sum = 0; for num in arguments sum += num; return sum; currySum = curry(addSum); currySum(1, 2, 3); currySum(1); currySum(1); currySum(1); currySum(1); currySum(); # 返回 10
实现原理其实也很简单,经过闭包,将每次的参数保存在args数组了。当不传参执行Getter时,就直接经过apply函数,将数组参数导入。咱们只须要在addSum函数那里处理好导入的参数数组便可。code
更多的柯里化带来的妙处,则须要你在实际使用中,细细品味。相信一旦你掌握了这个灵活可靠的方法,能够为你带来不同的感觉。ip