什么是柯里化?
f(x)和g(x)合成为f(g(x)),有一个隐藏的前提,就是f和g都只能接受一个参数,如果可以接收多个参数,比如 f(x, y) 和 g(a, b, c),函数合成就非常麻烦了。
这时就需要使用到函数柯里化了,所谓的“柯里化”,就是把一个多参数的函数,转化为单参数函数。如下:
// 柯里化之前
function add(x, y) {
return x + y;
}
add(1, 2) // 3
// 柯里化之后
function addX(y) {
return function (x) {
return x + y;
};
}
addX(2)(1) // 3
有了柯里化之后, 我们就能够做到,所有函数都只接受一个参数。
函数柯里化又称为部分求值,就是不会立即求值,而是等到了需要的时候再去求值。
有这样的一个场景,记录程序员一个月的加班总时间,那么好,我们首先要做的就是记录程序员每天加班的时间,然后把一个月中每天加班的时间相加,这样,就得到了一个月的加班总时间。
问题来了,我们又很多方法来实现,比如最简单的:
var monthTime = 0;
function overtime(time) {
return monthTime += time;
}
overtime(3.5); // 第一天
overtime(4.5); // 第二天
overtime(2.2); // 第三天
//...
//
//
//
overtime(3.2); // 第三十天
console.log(monthTime);
这个思路应该是最简单的,就是一个函数,变量时monthTime,每天加上加班小时数之后返回总的加班时间。
每次传入加班时间都进行累加,这样当然没问题,但你知道,如果数据量很大的情况下,这样会大大牺牲性能。
那怎么办?这就是柯里化要解决的问题。
其实我们不必每天都计算加班时间,只需要保存好每天的加班时间,在月底时计算这个月总共的加班时间,所以,其实只需要在月底计算一次就行。
即对于每次输入的时间,我们只需要保存起来即可,这样,没有了加法返回的步骤,就可以减少运算了。
如下所示的overtime函数还不是一个柯里化函数的完整实现,但是可以帮助我们了解其中的核心思想了:
这里的思想非常简单, 就是如果传入了参数,那么就把这个参数push到args数组中,表明这是在累加的阶段; 如果没有传入参数,那么就说明已经加完了,只要最后一次求和即可。 关键是这个overtime函数返回的是一个函数。 这里需要注意。如下:
var overtime = (function () {
var days = [];
return function () {
if (arguments.length == 1) {
[].push.apply(days, arguments);
} else {
var total = 0;
for (var i = 0; i < days.length; i++) {
total += days[i];
}
console.log(total);
return total;
}
}
})();
overtime(1);
overtime(2);
overtime(3);
overtime(4);
overtime(); // 10
即对于前面的四个overtime函数被调用的时候,其实只是保存了变量而已,并没有求值,直到最后才一起求值,这样有利于提高效率。