學習bind源代碼,比較bind的方式綁定函數在在內存使用上優於箭頭函數

前言

使用ES的class,究竟是使用箭頭函數更有效率,仍是在構造器函數(constructor)中使用bind函數給函數綁定context更加有效率?在Demystifying Memory Usage using ES6 React Classes文章中,給出了以下的結論。react

class properties

上圖是在class中使用箭頭函數建立類的方法。做者稱其爲class properties. 能夠看得出,使用箭頭函數在類中定義的handler方法,在其的每個實例中都會有一個獨立的handler函數。當實例的數量很少的時候,這種方式不會帶來很大的內存浪費,但當實例成千上萬的時候,這種方式就會顯得在內存使用上效率很低。如果可以共享類上的handler豈不是更好。es6

constructor bind

而使用構造器函數綁定,則可以更加有效的減小內存的使用。經過在構造器函數裏面綁定函數,以下代碼:bash

class MyClass extends Component {
  constructor() {
    super();
    this.state = { clicks: 0 };
    this.handler = this.handler.bind(this);
  }
  handler() {
    this.setState(({ clicks }) => ({ clicks: clicks + 1 }));
  }
  render() {
    const { clicks } = this.state;
    return(
      <button onClick={this.handler}>
        {`You've clicked me ${clicks} times`} </button> ); } } 複製代碼

每個實例裏面雖然都有handler方法(this.handler,不是MyClass.prototype.handler),但每一個實例中的this.handler實際上都共享MyClass.prototype.handler的函數體。app

那麼這是如何作到的呢? Bind函數MDN Polyfill實現:函數

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) { //oThis 表明object this
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this, //
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 // 獲取調用時(fBound)的傳參.bind 返回的函數入參每每是這麼傳遞的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 維護原型關係
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }; } 複製代碼

從上面的代碼能夠看出,咱們在構造器中使用bind綁定函數之後,實際上返回了一個函數(fBound),所返回的函數的函數體和待綁定(MyClass.prototype.handler)的函數體是不一樣的。所返回的函數只是在函數體內調用了待綁定的函數。換句話說,經過在構造器中使用bind綁定函數之後,所生成的實例中,都會有一個獨立的fBound,函數體相對於待綁定的函數較小,而每一個實例中的fBound在被調用時都會共享待綁定的函數(MyClass.prototype.handler)ui

結論

經過對比能夠發現,使用構造器bind的方法,每一個實例均可以有效地共享函數體,從而更加有效的使用內存。但當要綁定的函數較多時,這種方法又顯得相對的枯燥和無聊。因此,我認爲在知道實例很少,函數體不大的前提下,使用箭頭函數更加快捷。this

相關文章
相關標籤/搜索