市面上有很多currying的实现,实际上达成的效果都一致:我们有一个函数fn,通过currying(fn[, arg1][, arg2][, ...][, argn]),将fn包装为前n个参数固定的新函数,这里的n为currying中的arg数。
在看currying的时候,大家最爱用add函数的例子(参见1中建议阅读的几篇博文):
function add(x, y) {
return x + y;
}
通过以下方式可以固定add的第一个参数,产生从addZero到addNine的函数(先忽略掉currying及其注释说明,看currying对add产生的效果,这里主要看for(var key in dict)循环里的注释):
function gener() {
var currying = function(fn) {
// fn 要进行柯里化的函数
// args 固定下来的参数,可以多个
var args = [].slice.call(arguments, 1);
// 包装fn,里面的arguments是向包装后的fn传入的未固定参数,args已固定参数
return function() {
// 已经固化的参数args和新传入的参数arguments连接成新参数数组newArgs
var newArgs = args.concat([].slice.call(arguments));
// 包装原fn并返回,参数为newArgs,apply(null, [...])方便直接用数组参数newArgs调fn
return fn.apply(null, newArgs);
};
};
function add(a, b) {
return a + b;
}
var dict = {
addNine: 9, addEight: 8, addSeven: 7, addSix: 6, addFive: 5,
addFour: 4, addThree: 3, addTwo: 2, addOne: 1, addZero: 0
};
for(var key in dict) {
// 相当于执行(this是window):
// this.addNine = cuurying(add, 9)
// this.addEight = cuurying(add, 8)
// ...
// this.addZero = cuurying(add, 0)
// 其中,addNine是固化add的第一个参数为9的函数,其他同理
this[key] = currying(add, dict[key]);
}
}
gener();
console.log(['addZero(1): ' , addZero(1)].join('') );
console.log(['addOne(1): ' , addOne(1)].join('') );
console.log(['addTwo(1): ' , addTwo(1)].join('') );
console.log(['addThree(1): ', addThree(1)].join(''));
console.log(['addFour(1): ' , addFour(1)].join('') );
console.log(['addFive(1): ' , addFive(1)].join('') );
console.log(['addSix(1): ' , addSix(1)].join('') );
console.log(['addSeven(1): ', addSeven(1)].join(''));
console.log(['addEight(1): ', addEight(1)].join(''));
console.log(['addNine(1): ' , addNine(1)].join('') );
控制台输出:
上面代码中使用的currying函数如下(注释写得不好,希望能帮助理解,这里将上面的currying函数提出来放这里,它是实现柯里化的关键):
var currying = function(fn) {
// fn 要进行柯里化的函数
// args 固定下来的参数,可以多个
var args = [].slice.call(arguments, 1);
// 包装fn,里面的arguments是向包装后的fn传入的未固定参数,args已固定参数
return function() {
// 已经固化的参数args和新传入的参数arguments连接成新参数数组newArgs
var newArgs = args.concat([].slice.call(arguments));
// 包装原fn并返回,参数为newArgs,apply(null, [...])方便直接用数组参数newArgs调fn
return fn.apply(null, newArgs);
};
};