JavaScript高阶函数之柯里化与反柯里化

1. 什么是柯里化

柯里化函数把接收多个参数的函数变换成接收一个单一参数的函数再执行。

一个柯里化函数首先是会接收多个参数,但是接收这些参数之后,该函数并不会立即求值,而是继续返回另一个函数,刚才传入的参数在函数形成的闭包中被保存起来。等到函数被真正需要求值的时候,之前传入的所有参数会被一次性用于求值。

例如:计算月底的时候会花掉多少钱(如果在每个月的前 29 天,我们都只是保存好当天的开销,直到第 30 天才进行求值计算)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
var currying = function(fn) {
var args = [];
return function() {
if (arguments.length === 0) {
return fn.apply(this, args);
} else {
console.log(arguments)
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
//或者args = args.concat([].slice.call(arguments));
console.log(args)
return arguments.callee;
}
}
};
var cost = (function() {
var money = 0;
return function() {
for (var i = 0, l = arguments.length; i < l; i++) {
money += arguments[i];
}
return money;
}
})();
var cost = currying(cost); // 转化成 currying 函数
cost(100); // 未真正求值
cost(200); // 未真正求值 
cost(300); // 未真正求值
console.log(cost()); // 求值并输出:600

2.uncurrying反柯里化

反柯里化是指将接收单个参数的函数,转化为接收多个参数执行。

它解决的问题是让对象去借用一个原本不属于自己的方法。在JS的语言环境中,我们可以通过call和apply完成this的转化,同样,用uncurrying可以解决this的转化问题。

应用柯里化实现一个slice()函数:给函数原型添加一个方法,让这个方法借用JavaScript标准内置对象的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
Function.prototype.uncurrying = function() {
var self = this; //保存现场
return function() {
//借用Array对象shift()方法截去第一个参数,保存下来
var obj = Array.prototype.shift.call(arguments);
//给当前函数重新定义参数
return self.apply(obj,arguments);
};
};
//实现一个slice()函数:(返回的对象借用了Array对象slice()方法)
var slice = Array.prototype.slice.uncurrying();
var a = [1,2,3];
console.log(slice(a,1));// [2,3]

3.柯里化函数使用场景

1.缓存参数:

多次重复调用一个函数所传递的参数一样时,通过保存缓存的参数,后续的重复调用将不再走预处理流程。

2.提前传递部分参数:

当参数符合某些条件时进行相关操作。

2.惰性求值

当达到某些条件的时候,就把之前缓存的参数全部进行计算,例如水费,电费,每月开销等。

3.部分求值

4.反柯里化函数使用场景(主要可以扩大方法的使用范围)

1.可以让所有对象也拥有其他对象的方法。

原文地址:https://www.jdkdownload.com/js_currying.html