简介
柯里化函数是一种高阶函数,经过柯里化的函数的调用形式从原来的func(a, b, c, d)
变成支持func(a)(b)(c)(d)
。
柯里化的意义
假设有个将十进制数转为其他进制的函数,其定义如下:
// base为进制,比如2
function convertTo(base, number){
...
return x; //转换后的值
}
convertTo(2, 10); //10转为二进制
convertTo(2, 100);//100转为二进制
convertTo(2, 20); //20转为二进制
convertTo(16, 20); //20转为十六进制
现在将其柯里化,那么它的调用形式可以是这样的:
const convertToCurried = curry(convertTo);
convertToCurried(2, 10); //可以和之前一样调用
convertToCurried(2)(10); //10转为二进制
convertToCurried(2)(100);//100转为二进制
convertToCurried(2)(20); //20转为二进制
convertToCurried(16)(20); //20转为十六进制
现在,对于常用进制可以得到相应的进制转换函数了:
const convertToCurried = curry(convertTo);
//十进制转二进制函数
const convertToBinary = convertToCurried(2);
//十进制转十六进制函数
const convertToHexadecimal = convertToCurried(16);
convertToBinary(10); //10转为二进制
convertToBinary(100);//100转为二进制
convertToBinary(20); //20转为二进制
convertToHexadecimal(20); //20转为十六进制
实现
function curry(func) {
if(typeof func !== 'function'){
throw new TypeError("fisrt argument must be a function");
}
return function curriedFunc(...args) {
//函数都有个length属性表示该函数的形参个数
//只有当args的长度达到原函数的形参个数时才会真正执行原函数
if (args.length >= func.length) {
return func.apply(this, args);
} else {
//返回一个函数
return function(...args2) {
//调用该函数会将上次调用参数args与本次调用参数args2合并,继续柯里化,其实就是个递归过程
return curriedFunc.apply(this, args.concat(args2));
}
}
};
}
举个例子说明其过程
function sum(a,b,c){
return a + b +c;
}
const sumCurried = curry(sum);
/*
sum1 = function(...args2){
return curriedFunc.apply(this, [1].concat(args2));
}
*/
const sum1 = sumCurried(1);
/*
sum2 = function(...args2){
return curriedFunc.apply(this, [1,2].concat(args2));
}
*/
const sum2 = sum1(2);
// 调用sum2(3),由于此时args.length=3,满足if条件,所以 sum3 = sum.apply(this,[1,2,3])
const sum3 = sum2(3);
//整个过程完成,等价于sum3 = sumCurried(1)(2)(3);
需要注意的是,只有具有固定数量的参数的函数才能进行柯里化,使用剩余(rest)参数的函数,例如 function f(...args){}
是无法柯里化的。