JavaScript - 回调函数中作用域丢失

4

I have the following code:

var myPage = {};
myPage.component = function(callback){

    var somethingHappened = true;

    if (somethingHappened){
        callback();
    }
};

myPage.main = function(){

    // Initialise.
    this.init = function(){

        // make an instance of my component
        this.component = new myPage.component( this.callback );

        // need my utility function here
        this.doSomethingUseful();
    };

    // Callback to be executed when something happs in the component.
    this.callback = function(){
        this.doSomethingUseful(); // doesn't work
    };

    // A useful utility that needs to be accessible from both the 
    // init() and callback() functions
    this.doSomethingUseful = function(){
        // some utility stuff
    };
};
new myPage.main().init();

当组件执行回调函数时,我怎样才能确保myPage.main作用域可用呢?


this 关键字 与函数的变量作用域无关。 - Bergi
更好的方式是纠正某人,而不是仅仅声明他们是错误的。@Xoundboy,你在考虑上下文,而不是范围。 - Ilia Choly
3个回答

7

使用bind方法:

this.callback = function(){
    this.doSomethingUseful(); // doesn't work
}.bind(this);

这看起来是一种很好的传递作用域的干净方式,但我不确定其兼容性。根据你提供的链接,似乎我需要包含回退代码以支持那些不原生支持 .bind() 函数的浏览器。不过,目前我会尝试一下并查看是否有任何问题,并在必要时包含它。 - Xoundboy
该页面包含一个非常简单的polyfill。如果您需要提供兼容性,只需复制并粘贴所提供的代码即可。 - Matt Whipple
我刚试了一下,它运行得很好。我创建了一个 jsfiddle - http://jsfiddle.net/xoundboy/Vm5Tu/ - Xoundboy
在做ReactJS教程时,我对此感到非常生气。我将他们的匿名函数重写为类方法。但是当它们被用作回调时,它们会以某种方式失去上下文并不再属于一个类(WTF?!)。你的答案拯救了这一天。谢谢! - MickeyDickey

2
如果您想提供范围,可以使用Function.prototype.call
var foo = 'bar';
function(){
  // this = 'bar';
}.call(foo);

谢谢。我还不太清楚这在我的代码中如何工作。也许你可以详细说明一下 - 今晚有点累了 :) - Xoundboy
@Xoundboy:经过仔细观察您正在做的事情,您可能希望使用var self = this,这样在那些函数(this.init,this.callback,this.doSomethingUseful)中,您可以引用 myPage.main 的作用域。 - Brad Christie
你说得对 - 我简直不敢相信 - 这是我尝试的第一件事,但它没有起作用,这促使我提出这个问题。我一定打错了一个字 :/ - 不管怎样,我因此学到了.bind()和.call() 。并非都糟糕。这是使用您的建议的工作示例 - http://jsfiddle.net/xoundboy/uxy7n/ - Xoundboy

0

使用此函数实例化对象:

function newClass(klass) {
    var obj = new klass;

    $.map(obj, function(value, key) {
        if (typeof  value == "function") {
            obj[key] = value.bind(obj);
        }
    });

    return obj;
}

这将自动绑定所有函数,因此您将以习惯的面向对象编程风格获得对象, 当对象内的方法具有其对象的上下文时。

因此,您不通过以下方式实例化对象:

var obj = new myPage();

但是:

var obj = newClass(myPage);

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