JavaScript 回调范围

标签 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;
    }
};

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

var x = new foo('test');

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

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

最佳答案

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

问题出在下面一行:

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

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

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

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

由于在创建闭包时变量 self 被赋值 this,闭包函数将在稍后调用时记住 self 变量的值。

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

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

更新后的代码如下所示:

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

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

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

对于尚不支持 ES5 的浏览器,MDN provides the following shim :

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;  
  };  
} 

关于JavaScript 回调范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/183214/

相关文章:

c# - 将 DatagridComboboxColumn 绑定(bind)到集合

spring - 使用 @Value 将属性绑定(bind)到 Grails 中的闭包

javascript - 为什么无法通过JS访问该站点上的元素?

c# - AppDomain.CurrentDomain.Process退出和清理

javascript - window.scroll() 函数未触发

javascript - 人力车图表的 onClick 选项

c# - 如何从 XAML 中的 DataTemplate 引用匹配对象?

javascript - 避免一遍又一遍地写同一个词

javascript - 触发操作时出现回流错误

javascript - 用户单击时更改输入的背景颜色