Javasript設計模式之鏈式調用

寫過jquery的可能都知道,jquery裏面可以很方便的使用以下代碼:

// 不使用鏈式調用
const element = $(ele);
element.addClass('red');
element.removeClass('green');
element.show();

// 鏈式調用
$(ele)
  .addClass('red')
  .removeClass('green')
  .show();

而jquery這種調用方式就是鏈式調用。我們可以從上述代碼看出來,如果不使用鏈式調用的話,那麼我們會增加很多重複的代碼,而且特別冗餘。而通過鏈式調用,我們可以節省很多代碼,並且代碼看起來更加優雅和整潔。那麼,接下來,我們來討論下如何實現一個支持鏈式調用的庫。

瞭解過原型鏈的人都知道,由構造函數生成的實例都可以訪問其源性對象的屬性和方法,因此,我們只要讓定義在原型對象的方法最後都返回this(調用該方法的實例),就可以對原型方法進行鏈式調用。

// 通過立即執行函數,聲明瞭一個_$函數,並且將一個$函數掛載到window上,並且每次調用$()的時候,返回的其實是個_$實例,由於原型對象方法裏,執行最後都會返回一個this,因此就可以執行鏈式調用。
(function () {
  // 構造函數
  function _$(selector) {
    // ...
  }

  _$.prototype = {
    addClass: function (className) {
      // ...
      return this;
    },
    removeClass: function (className) {
      // ...
      return this;
    },
    show: function () {
      // ...
      return this;
    }
  };

  _$.prototype.constructor = _$;

  // 每次調用$()的時候,返回的其實是個_$實例
  window.$ = function () {
    return new _$(arguments);
  }
})();

// 通過這種方式,我們就可以直接使用$的鏈式調用
$(ele)
  .addClass('red')
  .removeClass('green')
  .show();

當然,上述代碼其實可以進行優化一下,因爲假設你引入的庫裏,已經有人定義了$函數,那麼就會面臨着命名衝突的問題。所以,我們可以爲其增加一個安裝器

(function () {
  // 構造函數
  function _$(selector) {
    // ...
  }

  _$.prototype = {
    addClass: function (className) {
      // ...
      return this;
    },
    removeClass: function (className) {
      // ...
      return this;
    },
    show: function () {
      // ...
      return this;
    }
  };

  _$.prototype.constructor = _$;

  // 增加一個安裝器
  window.installHelper = function (scope, interface) {
    scope[interface] = function () {
      return new _$(arguments);
    }
  }
})();

// 而用戶就可以這樣使用它來自定義掛載對象以及其命名
installHelper(window, '$');

$(ele).show();

當然,有時候鏈式調用並不是一個好的主意。鏈式調用適用於賦值器方法,但是對於取值器方法的話,就不是很友好。因爲我們有時候是想要方法返回一些數據,而不是返回一個this。對於這種情況的話,主要有兩種解決方法,一種是對於取值器方法就不返回this,直接返回數據。而另一種方法呢,則是通過回調方法來處理數據:

// 第一種方法,當遇到取值器,則直接返回數據
(function () {
  // 構造函數
  function _$(selector) {
    this.ele = document.querySelector(selector);
    // ...
  }

  _$.prototype = {
    addClass: function (className) {
      // ...
      return this;
    },
    // 取值器
    getClass: function () {
      // ...
      return this.ele.className;
    }
  };

  _$.prototype.constructor = _$;
})();

// 第二種方式,通過回調的方式來處理數據
(function () {
  // 構造函數
  function _$(selector) {
    this.ele = document.querySelector(selector);
    // ...
  }

  _$.prototype = {
    addClass: function (className) {
      // ...
      return this;
    },
    getClass: function (cb) {
      // ...
      cb.call(this, this.ele.className);
      return this;
    }
  };

  _$.prototype.constructor = _$;
})();

通過鏈式調用,我們可以簡化我們的代碼,讓代碼更加簡潔易讀。而我們只需要讓類所有的方法都返回this值,就可以讓該類變化一個支持方法鏈式調用的類。而如果要讓取值器方法也支持鏈式調用,就可以在取值器裏使用回調的方式來解決這個問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章