簡單理解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,轉載請與做者聯繫。不然將追究法律責任。

相關文章
相關標籤/搜索