小编典典

JavaScript回调范围

javascript

我在使用普通旧JavaScript(无框架)在回调函数中引用我的对象时遇到了一些麻烦。

function foo(id) {
    this.dom = document.getElementById(id);
    this.bar = 5;
    var self = this;
    this.dom.addEventListener("click", self.onclick, false);
}

foo.prototype = {
    onclick : function() {
        this.bar = 7;
    }
};

现在,当我创建一个新对象时(在DOM加载后,使用span#test)

var x = new foo('test');

onclick函数中的“ this”指向span#test而不是foo对象。

如何在onclick函数中获取对foo对象的引用?


阅读 281

收藏
2020-05-01

共1个答案

小编典典

(提取了一些其他答案的注释中隐藏的解释)

问题在于以下几行:

this.dom.addEventListener("click", self.onclick, false);

在这里,您传递了一个函数对象用作回调。当事件触发时,该函数被调用,但是现在它与任何对象(this)都没有关联。

可以通过将函数(及其对象引用)包装在闭包中来解决此问题,如下所示:

this.dom.addEventListener(
  "click",
  function(event) {self.onclick(event)},
  false);

由于在创建闭包时为变量self分配了 值,因此闭包函数将在以后调用self变量时记住它的值。

解决此问题的另一种方法是制作一个实用函数(并避免使用变量绑定 this ):

function bind(scope, fn) {
    return function () {
        fn.apply(scope, arguments);
    };
}

更新后的代码将如下所示:

this.dom.addEventListener("click", bind(this, this.onclick), false);

Function.prototype.bind是ECMAScript5的一部分,并提供相同的功能。因此,您可以执行以下操作:

this.dom.addEventListener("click", this.onclick.bind(this), false);

对于尚不支持ES5的浏览器,MDN提供以下填充程序:

if (!Function.prototype.bind) {  
  Function.prototype.bind = function (oThis) {  
    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 || window,  
                               aArgs.concat(Array.prototype.slice.call(arguments)));  
        };

    fNOP.prototype = this.prototype;  
    fBound.prototype = new fNOP();

    return fBound;  
  };  
}
2020-05-01