什么是currying/柯里化
- 百度百科中是这么解释的:柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
- 忍者秘籍中是这么解释的:在一个函数中首先填充几个参数(然后再返回一个新函数)的技术称为柯里化(Currying)。
如果看这些概念你不是特别清楚那么我们接下来看一个实例:
let add1 = function(a,b,c){
return a+b+c;
}
let add2 = function(a){//函数柯里化
return function(b){
return function(c){
return a+b+c;
}
}
}
console.log(add1(1,2,3));//6
console.log(add2(1)(2)(3));//6
是不是感觉和闭包有点类似,恩 其实实质利用的就是闭包的概念,本质上讲柯里化(Currying)只是一个理论模型,柯里化所要表达是:如果你固定某些参数,你将得到接受余下参数的一个函数。
柯里化实例
当然,柯里化的参数是不固定的,假设我现在有n个数需要求和操作我们应该怎么写
let add = function () {
let _args = [];
return function () {
if (arguments.length === 0) {
return _args.reduce(function (a, b) {
return a + b;
});
}
[].push.apply(_args, [].slice.call(arguments));
return arguments.callee;
}
};
let sum = add()
sum(1,2)(3); // 调用形式灵活,一次调用可输入一个或者多个参数
console.log(sum()); // 6(最后在进行计算输出)
上面 add是柯里化了的函数,它返回一个新的函数,新的函数可接收新的参数,延迟到最后一次计算。
基础知识讲解
arguments
函数有个内置的对象 arguments 对象。argument 对象包含了函数调用的参数数组。
arguments.callee
arguments.callee该属性是一个指针,指向拥有这个arguments对象的函数。由于严格模式下不能使用arguments.callee所以,我们可以改进一下上面的add函数。
let add = function () {
let _args = [];
return function fn () {
if (arguments.length === 0) {
return _args.reduce(function (a, b) {
return a + b;
});
}
[].push.apply(_args, [].slice.call(arguments));
return fn;
}
};
let sum = add()
sum(1,2)(3); // 调用形式灵活,一次调用可输入一个或者多个参数
console.log(sum()); // 6(最后在进行计算输出)
[].push.apply(_args, [].slice.call(arguments));
这个方法等同于Array.prototype.push.apply(_args,Array.prototype.slice.call(arguments));这个方法实现了将arguments合并到 _args中与 _args = _args.concat([].slice.call(arguments));类似。
封装柯里化函数
我们既然知道了柯里化函数是什么,那么我们可以将它封装成一个函数
let currying = function (callback){//参数中放入一个回调函数
let _args = [];//声明一个参数数组
return function fn(){
if(arguments.length===0){
return callback.apply(this,_args);
}
_args = _args.concat([].slice.call(arguments));
return fn;
}
};
使用
let add = function () {
let sum = 0;
for (let i = 0, c; c = arguments[i++];) {
sum += c;
}
return sum;
};
let sum = currying(add);
sum(1,2)(3);
console.log(sum());//6
当然,当大家看到这里时是不是觉得柯里化好像在平时用不上,那么大家觉得bind函数用的多吗?其实bind函数你们就可以看成另一种柯里化。