什么是柯里化
柯里化是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下参数的新函数的技术。
比如说,sum(2, 3)可以转换成sum(2)(3)。
柯里化有什么用
柯里化的好处在于,调用函数的时候,如果某一个参数在每次调用中都相同,可以避免重复传入这个参数。
举个栗子
判断n个用户是否是当前用户,假设当前用户为user
,要比较的为user1
,user2
,… ,usern
柯里化前
function isSameUser(ua,ub){
...
return ua == ub;
}
//调用n次:
let res1 = isSameUser(user,user1);
let res2 = isSameUser(user,user2);
let res3 = isSameUser(user,user3);
let res4 = isSameUser(user,user4);
...
let resn = isSameUser(user,usern);
以上例子中,每次调用都需要传入user这个对象。
使用柯里化优化
function isSameUser(ua,ub){
...
return ua == ub;
}
function curry(fn){
...
//return 处理后的fn,并固化参数user
return newFn;
}
var isUser = curry(isSameUser)(user);
//调用n次:
let res1 = isUser(user1);
let res2 = isUser(user2);
let res3 = isUser(user3);
let res4 = isUser(user4);
...
let resn = isUser(usern);
再比如
function simpleURL(protocol, domain, path) {
return protocol + "://" + domain + "/" + path;
}
这个函数是将三个参数生成一个完成的url.调用如下:
var myurl = simpleURL('http', 'mysite', 'home.html');
var myurl2 = simpleURL('http', 'mysite', 'aboutme.html');
很明显,每次调用时前两个参数保持不变,但每次调用都需要传递。所以可以对其优化,仅传递最后一个变化的参数。
如果将函数改成如下:
function simpleURL(path) {
return "http://mysite/" + path;
}
如果这个库函数有被其它人使用呢,这种情况下基本上是不允许直接改库函数的。并且如果后期还需要处理https的请求呢。难道再把第一个参数加回去?这样别人若使用了该库函数也要修改调用代码。
针对这种情况,使用柯里化函数可以完美解决。
// 避免每次调用重复传参,此处使用lodash.curry
let myURL1 = _.curry(simpleURL)('https', 'mysite');
let res1 = myURL1('home.html'); //
console.log(res1);//https://mysite/home.html
let myURL2 = _.curry(simpleURL)('http', 'mysite');
let res2 = myURL2('aboutme.html'); //
console.log(res2);//http://mysite/aboutme.html
关于实现
以下提供一个简单的手动实现
function _currying(fn, length) {
return function (...args) {
if (args.length >= length) {
return fn(...args)
}
return _currying(fn.bind(null, ...args), length - args.length)
}
}
function add(...args) {
return args.reduce((a, b) => a + b)
}
add = _currying(add, 7)
console.log(add(1)(2)(3)(4)(5)(6)(7));
柯里化这个概念以及实现本身都比较难懂,平时写代码大多数情况都选择了其它简单的方式实现了。在get到这个技能后,我认为以后可以在项目中适当使用这个方法,尽量减少重复代码。目前只研究了这么些,至于其它的好处和使用场景后期有机会再更新。