从回调函数中调用一个JavaScript对象的方法

24

我在一个用户脚本中定义了以下MyClass及其方法:

function MyClass() {
    this.myCallback = function() {
        alert("MyClass.myCallback()");
    };

    this.startRequest = function() {
        GM_xmlhttpRequest({
            'method': 'GET',
            'url': "http://www.google.com/",
            'onload': function (xhr) {
                myClassInstance.myCallback();
            }
        });
    };
}

var myClassInstance = new MyClass();
myClassInstance.startRequest();

这个脚本可以运行,myCallback() 方法在 GM_xmlhttpRequest 完成后被调用。

但是,它之所以能够工作,是因为 onload 回调引用了全局变量 myClassInstance。如果我将 onload 回调更新为:

'onload': function (xhr) {
    this.myCallback();
}

然后我收到(Chrome)错误:

Uncaught TypeError:Object [object DOMWindow]没有'myCallback'方法。

看起来this在错误的上下文中被评估。

是否有一种方法可以调用myClassInstancemyCallback()方法,而不必使用全局变量?

3个回答

40

将正确的this在其作用域内存入一个变量中,然后就可以稍后引用它:

 this.startRequest = function() {
     var myself = this;
     GM_xmlhttpRequest({
         'method': 'GET',
         'url': "http://www.google.com/",
         'onload': function (xhr) {
             myself.myCallback();
         }
     });
 };

7
+1 你刚刚结束了我长达一个小时的头痛苦思考。谢谢你。 :) - Anthony

7

最简单的解决方案,就像已经指出的那样,是为保持作用域中的this创建一个别名。最流行的变量名称为别名是selfthat,但实际上任何名称都可以。

另一种选择(根据使用情况可能更好或更差)是将方法绑定到“普通”函数中,并使用该函数:

var f = this.callback.bind(this);

...
'onload': function(){
    f();
}

旧版本浏览器不支持bind,但许多JS框架中都可以找到替代品。我提供的示例并不是很好,但在您想要直接将方法作为回调函数传递时,它可以非常方便(您还可以获得部分函数应用程序,这非常整洁)。


3
小心使用 self,因为会涉及到 window.self - Jeremy

3

存储实例的引用并使用它:

function MyClass() {
    this.myCallback = function() {
        alert("MyClass.myCallback()");
    };

    var instance = this;

    instance.startRequest = function() {
        GM_xmlhttpRequest({
            'method': 'GET',
            'url': "http://www.google.com/",
            'onload': function (xhr) {
                instance.myCallback();
            }
        });
    };
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接