JavaScript柯里化

什么是柯里化

柯里化允许我们把函数与传递给它的参数结合,产生一个新的函数。[引自《JavaScript语言精髓》,第43页 柯里化]

A function is said to be curried when not all arguments have been supplied to the function, so it returns another function that retains the arguments given and expects the remaining arguments.[引自《JavaScript: Novice to Ninja》,第317页 Currying]

当一个函数没有传入全部所需参数时,它会返回另一个函数(这个返回的函数会记录那些已经传入的参数),这种情况叫作柯里化。 简单的说柯里化就是通过传入函数所需的部分参数,将一个函数分割为多个的一种技术。

参考如下例子:

function multiplier(x, y){
    if(y===undefined){
        return function(z){
            return x * z;
        }
    }else{
        return x*y;
    }
}

当只传入参数x的时候multiplier会返回一个新的函数,并且这个函数会记录之前传递的x的值(闭包特性)。 这时如下两种调用是等价的:

multiplier(3, 4);
multiplier(3)(4);

通用的柯里化方法

[代码引自《JavaScript: Novice to Ninja》,第319页 A General Curry Function]

function curry(func) {
  var fixedArgs = [].slice.call(arguments,1);
  return function() {
    args = fixedArgs.concat([].slice.call(arguments))
    return func.apply(null, args);
  };
}

以以下例子说明curry运行过程。

function divider(x,y) {
  return x/y;
}
reciprocal = curry(divider,1);
reciprocal(2);

执行reciprocal(2)相当于执行curry(divider,1)(2)。然后看curry方法通过[].slice方法去掉了传入的第一个参数,即function divider(x,y) {return x/y;},之后保留了变量x=1并返回一个新的函数,这是一个匿名函数,同时传入变量y=2,这时fixedArgs.concat([].slice.call(arguments))将之前传入的变量x和现在传入的变量y重新组合成一个数组,最后执行函数divider,这时使用的参数是组合后的[1,2]。整个curry方法主要工作就是组织两次传入的参数,然后通过apply方式调用函数。

柯里化作用

Curring allows you to turn a single function into a series of functions instead. This is useful if you find that you’re constantly calling a function with the same argument.[代码引自《JavaScript: Novice to Ninja》,第318页]

柯里化允许你将一个函数转换为一些列函数,在经常调用一个相同参数的函数时,柯里化是很好的解决方案。 比如要做一个打折运算时,tax = multiplier(0.22,400);这个折扣基本都0.22的情况下,就可以定义一个函数calcTax = multiplier(0.22);这样再作这个折扣计算时就省去了一个参数的传递:calcTax(400);。

命名由来

The name "currying", coined by Christopher Strachey in 1967, is a reference to logician Haskell Curry[引自维基百科, currying, naming]

柯里化命名来源于Haskell Curry,Moses Schönfinkel提出这个概念后,Haskell Curry通过计算机实现了它。后来于1967年由Christopher Strachey命名为curying。

参考博客:

浅析 JavaScript 中的 函数 currying 柯里化

为什么要柯里化

函数解析

slice