回撥和 this

通常在使用回撥時,你希望訪問特定的上下文。

function SomeClass(msg, elem) {
  this.msg = msg;
  elem.addEventListener('click', function() {
    console.log(this.msg);  // <= will fail because "this" is undefined
  });
}

var s = new SomeClass("hello", someElement);

解決方案

  • 使用 bind

    bind 有效地生成一個新函式,將 this 設定為傳遞給 bind 的任何內容,然後呼叫原始函式。

      function SomeClass(msg, elem) {
        this.msg = msg;
        elem.addEventListener('click', function() {
          console.log(this.msg);  
        }.bind(this));  // <=-  bind the function to `this`
      }
    
  • 使用箭頭函式

    箭頭函式自動繫結當前的 this 上下文。

      function SomeClass(msg, elem) {
        this.msg = msg;
        elem.addEventListener('click',() => {   // <=-  arrow function binds `this`
          console.log(this.msg);  
        });
      }
    

通常,你希望呼叫成員函式,理想情況下將傳遞給事件的任何引數傳遞給函式。

解決方案:

  • 使用 bind

      function SomeClass(msg, elem) {
        this.msg = msg;
        elem.addEventListener('click', this.handleClick.bind(this));
      }
    
      SomeClass.prototype.handleClick = function(event) {
        console.log(event.type, this.msg);
      };
    
  • 使用箭頭函式和其餘運算子

      function SomeClass(msg, elem) {
        this.msg = msg;
        elem.addEventListener('click', (...a) => this.handleClick(...a));
      }
    
      SomeClass.prototype.handleClick = function(event) {
        console.log(event.type, this.msg);
      };
    
  • 特別是對於 DOM 事件監聽器,你可以實現 EventListener 介面

      function SomeClass(msg, elem) {
        this.msg = msg;
        elem.addEventListener('click', this);
      }
    
      SomeClass.prototype.handleEvent = function(event) {
        var fn = this[event.type];
        if (fn) {
           fn.apply(this, arguments);
        }
      };
    
      SomeClass.prototype.click = function(event) {
        console.log(this.msg);
      };