JavaScript 回调范围 [英] JavaScript Callback Scope

查看:23
本文介绍了JavaScript 回调范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm having some trouble with plain old JavaScript (no frameworks) in referencing my object in a callback function.

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)

Now when I create a new object (after the DOM has loaded, with a span#test)

var x = new foo('test');

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

The 'this' inside the onclick function points to the span#test and not the foo object.

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

How do I get a reference to my foo object inside the onclick function?

推荐答案

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

问题出在以下几行:

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

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

Here, you pass a function object to be used as callback. When the event trigger, the function is called but now it has no association with any object (this).

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

The problem can be solved by wrapping the function (with it's object reference) in a closure as follows:

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

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

Since the variable self was assigned this when the closure was created, the closure function will remember the value of the self variable when it's called at a later time.

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

An alternative way to solve this is to make an utility function (and avoid using variables for binding this):

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

更新后的代码如下所示:

The updated code would then look like:

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

<小时>

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


Function.prototype.bind is part of ECMAScript 5 and provides the same functionality. So you can do:

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

对于尚不支持 ES5 的浏览器,MDN 提供了以下垫片:

For browsers which do not support ES5 yet, 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 回调范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆