什么是柯里化?
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函数被调用的时候,其实只是保存了变量而已,并没有求值,直到最后才一起求值,这样有利于提高效率。
https://rockjins.js.org/2017/02/15/2017-02-15-curring-uncurring/