JavaScript 柯里化(Currying)
1. 什么是柯里化(Currying)
柯里化是对函数的转换,将函数调用由 f(a, b, c)
转换成 f(a)(b)(c)
。
2. 柯里化的目的
下面以 lodash 库的 _.curry 为例来说明柯里化的作用。该方法会返回一个包装器,该包装器允许函数被正常调用或者以 partial
的方式调用
function sum(a, b) {
return a + b;
}
let curriedSum = _.curry(sum);
console.log(curriedSum(1, 2)); // 正常调用,3
console.log(curriedSum(1)(2)); // partial调用,3
柯里化的作用主要在于获取部分应用函数(partial)。如果我们总是要计算某一值和99相加的结果:
const sum99 = curriedSum(99);
console.log(sum99(1)); // 100, 99 + 1
console.log(sum99(70)); // 169, 99 + 70
// 同理,总求与80的和
const sum80 = curriedSum(80);
console.log(sum80(1)); // 81, 80 + 1
3. 柯里化实现
function curry(func) {
return function curried(...args) {
if(args.length >= func.length) {
return func.apply(this, args);
} else {
return function(...args2){
return curried.apply(this, args.concat(args2));
}
}
}
}
- 注意:
柯里化要求函数具有固定数量的参数,如f(...args)
则不能以这种方式进行柯里化
4. uncurrying
实现 uncurrying
Function.prototype.uncurrying = function() {
const self = this;
return function(){
const obj = Array.prototype.shift.call(arguments);
return self.apply(obj, arguments);
}
}
或者
Function.prototype.uncurrying = function() {
const self = this;
return function(){
return Function.prototype.call.apply(self, arguments);
}
}
在类数组对象 arguments 借用 Array.prototype
的方法之前,我们可以先把 Array.prototype.push.call
转成一个通用的 push 函数
const push = Array.prototype.push.uncurrying();
(function(){
push(arguments, 4);
console.log(arguments); // [1, 2, 3, 4]
})(1, 2, 3);