一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
前言
之前就在一些地方看到过函数柯里化这个名词,但一直不带明白到底是什么意思,到底是干嘛用的,今天有空学习一下,顺便做个总结
函数柯里化的定义
上图是百度词条对柯里化的定义,我个人的理解总结为一句话就是把一个多参数的函数转换成多个只要一个参数的函数。柯里化在很多地方都用的到,不止是在编程中。
初是柯里化
先来看一段代码
function sum(x,y){
return x+y
}
sum(2,3) //这里就是正常的调用sum函数进行求和,传入了两个参数
var addCurry = curry(sum) //这里的curry就是柯里化函数
addCurry(2)(3)
柯里化的作用
- 提高适用行,减少重复参数的输入
- 可以起到延迟执行的作用,因为要等到传入的参数和原函数需要的参数个数一样的时候才会执行函数获取结果】
- 降低通用性
实现柯里化函数
var curry = function (fn) {
var args = [].slice.call(arguments, 1);//这里是获取柯里化时是否已经传入了参数
return function () {
var newArgs = args.concat([].slice.call(arguments)); //这里把柯里化时传入的参数和调用柯里化后的函数传入的参数进行合并
return fn.apply(this, newArgs); //将合并后的参数传递给fn
};
};
function addNum(a, b) {
return a + b ;
}
const addCurry = curry(addNum);
console.log(addCurry(1,2))
上述代码只实现了不符柯里化,比如支持了addCurry(1,2)这种输入,但是不支持addCurry(1)(2)这种输入,下面来一个可以使用多重格式的代码,如下:
function myCurry(fn, args) {
var length = fn.length; //这里通过fn.length来获得目标函数的形参数量
args = args || [];
return function () { //返回一个匿名函数
var _args = args.slice(0),
arg, i;
for (i = 0; i < arguments.length; i++) {
arg = arguments[i];
_args.push(arg);
}
if (_args.length < length) { //这里判断多次传入的参数个数是否达到了目标函数需要的形参个数,如果没达到就递归调用myCurry()
return myCurry.call(this, fn, _args);
}
else {
return fn.apply(this, _args); //如果多次传入的参数个数达到了目标函数所需要的形参个数,就直接调用目标函数
}
}
}
var fn = myCurry(function (a, b, c) {
console.log([a, b, c]);
});
fn("1", "2", "3") // ["1", "2", "3"]
fn("1", "2")("3") // ["1", "2", "3"]
fn("1")("2")("3") // ["1", "2", "3"]
fn("1")("2", "3") // ["1", "2", "3"]
总结
柯里化函数总结为一句话就是,把一个需要多个参数的函数通过柯里化函数的处理变成多个需要单个参数的函数。也就是说通过闭包把参数先保存起来,当参数的个数足够执行原函数了,就开始执行原函数。