简单理解JavaScript中的柯里化和反柯里化

就像最先听到斐波拉切数列同样,第一次听到柯里化我也是懵逼的javascript

本文参考:

  1. JavaScript设计模式与开发实践java

  2. Currying in JavaScriptgit

  3. Curried JavaScript functions程序员

前言

本文旨在让你们简单理解柯里化和反柯里化,这里不作深刻探究,只求能带你们装逼就好,看完还不懂你砍我。github

咱们先来简单了解一下他们的做用。设计模式

柯里化又称部分求值,字面意思就是不会马上求值,而是到了须要的时候再去求值。若是看的懵逼,没事,看完整篇文章再回过头来看这里你就会豁然开朗。微信

反柯里化的做用是,当咱们调用某个方法,不用考虑这个对象在被设计时,是否拥有这个方法,只要这个方法适用于它,咱们就能够对这个对象使用它。app

柯里化(curring)

咱们有这样一个场景,记录程序员一个月的加班总时间,那么好,咱们首先要作的是记录程序员天天加班的时间,而后把一个月中天天的加班的时间相加,就获得了一个月的加班总时间。函数

但问题来了,咱们有不少种方法能够实现它,好比最简单的:性能

var monthTime = 0;

function overtime(time) {
 return monthTime += time;
}

overtime(3.5);    // 第一天
overtime(4.5);    // 次日
overtime(2.1);    // 第三天
//...

console.log(monthTime);    // 10.1复制代码

每次传入加班时间都进行累加,这样固然没问题,但你知道,若是数据量很大的状况下,这样会大大牺牲性能。

那怎么办?这就是柯里化要解决的问题。

其实咱们没必要天天都计算加班时间,只须要保存好天天的加班时间,在月底时计算这个月总共的加班时间,因此,其实只须要在月底计算一次就行。

下面的overtime函数还不是一个柯里化函数的完整实现,但能够帮助咱们了解其核心思想:

var overtime = (function() {
  var args = [];

  return function() {
    if(arguments.length === 0) {
      var time = 0;
      for (var i = 0, l = args.length; i < l; i++) {
        time += args[i];
      }
      return time;
    }else {
      [].push.apply(args, arguments);
    }
  }
})();

overtime(3.5);    // 第一天
overtime(4.5);    // 次日
overtime(2.1);    // 第三天
//...

console.log( overtime() );    // 10.1复制代码

柯里化的核心思想就是这样,看到这里你确定已经懂了,至于真正的柯里化函数,网上有不少,你们能够去Google一下。

反柯里化(uncurring)

反柯里化的的做用已经在前言说过了,这里讲下它的由来。

2011年JavaScript之父Brendan Eich发表了一篇Twitter,提出了反柯里化这个思想,下面这段代码是反柯里化的实现方式之一:

Function.prototype.uncurring = function() {
  var self = this;
  return function() {
    var obj = Array.prototype.shift.call(arguments);
    return self.apply(obj, arguments);
  };
};复制代码

咱们先来看看上面这段代码有什么做用。

咱们要把Array.prototype.push方法转换成一个通用的push函数,只须要这样作:

var push = Array.prototype.push.uncurring();

//测试一下
(function() {
  push(arguments, 4);
  console.log(arguments); //[1, 2, 3, 4]
})(1, 2, 3)复制代码

arguments原本是没有push方法的,一般,咱们都须要用Array.prototype.push.call来实现push方法,但如今,直接调用push函数,既简洁又意图明了。

就和前言写的那样,咱们不用考虑对象是否拥有这个方法,只要它适用于这个方法,那就可使用这个方法(相似于鸭子类型)。

咱们来分析一下调用Array.prototype.push.uncurring()这句代码时,发生了什么事情:

Function.prototype.uncurring = function() {
  var self = this;  //self此时是Array.prototype.push

  return function() {
    var obj = Array.prototype.shift.call(arguments);
    //obj 是{
    // "length": 1,
    // "0": 1
    //}
    //arguments的第一个对象被截去(也就是调用push方法的对象),剩下[2]

    return self.apply(obj, arguments);
    //至关于Array.prototype.push.apply(obj, 2);
  };
};

//测试一下
var push = Array.prototype.push.uncurring();
var obj = {
  "length": 1,
  "0" : 1
};

push(obj, 2);
console.log( obj ); //{0: 1,1: 2, length: 2 }复制代码

看到这里你应该对柯里化和反柯里化有了一个初步的认识了,但要熟练的运用在开发中,还须要咱们更深刻的去了解它们内在的含义。

喜欢本文的朋友能够关注个人微信公众号,不按期推送一些好文。

本文出自Rockjins Blog,转载请与做者联系。不然将追究法律责任。

相关文章
相关标签/搜索