什么是函数的柯里化?
将一个函数与其参数的子集绑定到一个闭包中,并且返回这个闭包。
通俗地说,只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
假设你有这样一个拼接字符串的函数,代码如下:
| 1 2 3 4 5
 | 'use strict'; var getUrl = function (protocal, domain, path) {   return protocal + '://' + domain + '/' + path; };
 | 
这是一个再普通不过的函数,它需要我们提供3个参数,并且返回最终拼接的url。
但是结合实际来看,我们通常不需要每次都设置protocal和domain参数,因为他们不是经常变化的。怎么办呢?也许我们会想把该函数改成单参的不就行了吗?
| 1 2 3 4 5
 | var getUrl = function (path) {   return 'http://abc.com/' + path; }; getUrl('http', 'www.xwjgo.com', 'index.html');  
 | 
这样改存在一些问题,比如我们要给站点加上SSL,我们总不能把第一个参数再放回去。所以,这个问题正确解决方式应该是柯里化;
柯里化的实现
柯里化可以使用Function.prototype.bind()来实现,通常我们不需要重复造轮子,不过为了加深对柯里化的了解,这里将通过自己的函数来实现柯里化。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 | 'use strict'; var getUrl = function (protocal, domain, path) {   return protocal + '://' + domain + '/' + path; }; var currying = function (fn) {      var args = Array.prototype.slice.call(arguments, 1);      return function () {          var innerArgs = Array.prototype.slice.call(arguments);          var allArgs = args.concat(innerArgs);          return fn.apply(null, allArgs);   }; }; var getUrlByPath = currying(getUrl, 'https', 'www.abc.com'); var getUrlByDomainAndPath = currying(getUrl, 'http'); getUrlByPath('index.html');                         getUrlByDomainAndPath('www.123.com', 'abc.html');  
 | 
以上代码在ES6中将会更加简介:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 | 'use strict'; var getUrl = (protocal, domain, path) => protocal + '://' + domain + '/' + path; var currying = (fn, ...rest) => {      return (...innerRest) => {          var allArgs = rest.concat(innerRest);          return fn(...allArgs);   }; }; var getUrlByPath = currying(getUrl, 'https', 'www.abc.com'); var getUrlByDomainAndPath = currying(getUrl, 'http'); getUrlByPath('index.html');                         getUrlByDomainAndPath('www.123.com', 'abc.html');  
 | 
| 1 2 3 4 5 6 7 8 9
 | 'use strict'; var getUrl = (protocal, domain, path) => protocal + '://' + domain + '/' + path;        var getUrlByPath = getUrl.bind(null, 'https', 'www.hyy.com'); var getUrlByDomainAndPath = getUrl.bind(null, 'http'); getUrlByPath('docs/currying.html');                   getUrlByDomainAndPath('www.abc.com', 'index.html');  
 | 
bind函数会创建一个新函数,称为绑定函数。新函数与被调函数具有相同的函数体。
当新函数被调用时,其中的this指向bind函数的第一个参数,而后续的可选参数会被插入到新函数参数列表的开始位置。
柯里化的作用
上面说明了柯里化的实现和原理。那么,柯里化有什么作用呢?它的作用主要体现在以下三个方面:
- 参数复用
- 延迟执行
- 使程序更加纯粹
其中参数复用,通过上面的代码已经可以解释。
而延迟执行是因为,currying函数返回一个待执行的函数,而不是函数的执行结果。
第三点可以参考这篇文章。