JavaScript回调范围

Chr*_*ald 58 javascript events binding scope callback

我在回调函数中引用我的对象时遇到了一些普通的旧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;
    }
};
Run Code Online (Sandbox Code Playgroud)

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

var x = new foo('test');
Run Code Online (Sandbox Code Playgroud)

onclick函数中的'this'指向span#test而不是foo对象.

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

his*_*dow 81

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

问题在于以下几行:

this.dom.addEventListener("click", self.onclick, false);
Run Code Online (Sandbox Code Playgroud)

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

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

this.dom.addEventListener(
  "click",
  function(event) {self.onclick(event)},
  false);
Run Code Online (Sandbox Code Playgroud)

由于自变量分配创建关闭时,关闭功能会记得自变量的值时,它被称为在以后的时间.

解决此问题的另一种方法是创建一个实用程序函数(并避免使用变量来绑定):

function bind(scope, fn) {
    return function () {
        fn.apply(scope, arguments);
    };
}
Run Code Online (Sandbox Code Playgroud)

更新的代码将如下所示:

this.dom.addEventListener("click", bind(this, this.onclick), false);
Run Code Online (Sandbox Code Playgroud)

Function.prototype.bind是ECMAScript 5的一部分,并提供相同的功能.所以你可以这样做:

this.dom.addEventListener("click", this.onclick.bind(this), false);
Run Code Online (Sandbox Code Playgroud)

对于不支持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;  
  };  
} 
Run Code Online (Sandbox Code Playgroud)

  • 或者bind()或bindMethod(). (2认同)

Ser*_*sky 15

this.dom.addEventListener("click", function(event) {
    self.onclick(event)
}, false);
Run Code Online (Sandbox Code Playgroud)

  • 当您在问题中使用表单时,self.onclick只是一个匿名函数,在处理时,就像您将其直接附加到跨度一样.当你将它包装在一个闭包中时,self.onclick(event)确实可以做你想要的,例如在定义闭包的上下文中使用'self'. (2认同)

Sel*_*aek 5

对于寻找此问题的解决方案的jQuery用户,您应该使用jQuery.proxy