我理解的函数柯里化

2,616 阅读2分钟

对于函数柯里化之前就了解过,大概知道是个什么东西。
最近在读Vue源码的时候,看到了 cached 函数的使用,让我觉得这个代码写的挺有意思,于是在sg发问,看了 @sunyongjian 回答,于是又绕到了 柯里化高阶函数上

柯里化定义

维基中有对柯里化的定义:在计算机科学中,柯里化(英语:Currying),又译为卡瑞化加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

用JavaScript表达定义

着重看 多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数

var foo = function(a) {
    return function (b) {
        return function (c) {
            return a+b+c;
        };
    };
};

使用

foo(1) // f (b) {  return function(c) { return a+b+c } }
foo(1)(2) // f (c) {  return a+b+c }
foo(1)(2)(3)  // 6

其实就是逐渐消元的过程。知乎上也有类似的问题,具体见:如何理解functional programming里的currying与partial application

通用的柯里化函数

上面的例子虽然解释了什么是柯里化,但是还不通用,因为 参数个数 理论上是无法估计的。

下面就是一个抽象的柯里化函数

var toCurring = function(fn){
        var _args = [];
        function cb(){
            if(arguments.length === 0) {
                return fn.apply(this, _args);
            }

            Array.prototype.push.apply(_args, [].slice.call(arguments));

            return cb;
        }
        return cb;
    }

场景使用

实际场景的运用能更好的加深我们的理解,所以我们用实际的生活场景来看看 柯里化 如何运用。

场景:记账本,每天记录使用多少钱,一个月算一次总花费(或者在我想要知道的时候)

function account(){
   var total = [];
   function money(p) {
     if (arguments.length === 0) {
       // 计算一共花了多少钱
       total = total.reduce((sum, value) => {
          return sum + value;
       }, 0)
       console.log('一共花了', total+' 元');
     } else {
       // 记录每天花了多少钱
       total.push(p)
       console.log('今天花了', p+' 元');
     }
   }
   return money;
}

这个我们就定义好了一个 柯里化 的记账本。
我们来用一下

var spend = account();
spend(15) // 今天花了 15 元
spend(30) // 今天花了 30 元
spend() // 一共花了 45 元 (不传参数的时候就返回真正的结果)

Tip:高阶函数:一个函数接收另一个函数作为其参数。