0

谁能告诉我为什么这不起作用?

(function() {
    window.Test = {};
})();

Test.Timers = {
    c: null,
    startTimer: function() { c = 0; setTimeout(this.doWork, 0); },
    doWork: function() {
        c++;
        alert(c);
        setTimeout(this.doWork, 0);
    }
};

当我调用 Test.Timers.startTimer() 时,它只会用 1 发出一次警报。谢谢

4

2 回答 2

1

一个方法不会“记住”它的所有者(它的this);您可以将方法从一个对象复制到另一个对象,并像对待任何其他函数一样对待它。只有当您使用点符号实际调用它时,它才具有正确的所有者,例如this.doWork().

所以你的问题是你将函数传递this.doWorksetTimeout,然后它在不知道它的所有者的情况下作为一个函数被调用,突然它thiswindow不是你的计时器对象。要解决此问题,您需要跟踪this自己。例如,你可以写:

Test.Timers = (function () {
    var newTimer = {
        c: null,
        startTimer: function() {
            this.c = 0;
            setTimeout(function () { newTimer.doWork(); }, 0);
        },
        doWork: function() {
            this.c++;
            alert(this.c);
            setTimeout(function () { newTimer.doWork(); }, 0);
        }
    };
    return newTimer;
 })();

或者:

Test.Timers = (function () {
    var startTimer = function() {
        newTimer.c = 0;
        setTimeout(doWork, 0);
    };
    var doWork = function() {
        newTimer.c++;
        alert(newTimer.c);
        setTimeout(doWork, 0);
    };
    var newTimer = {
        c: null,
        startTimer: startTimer,
        doWork: doWork
    };
    return newTimer;
 })();

(注意,我也改成cthis.cor newTimer.c,因为你的版本重复引用window.c。还要注意,在第二个版本中,如果你不需要外部代码就可以访问c,你可以将其更改为局部变量,使得东西更干净。)

于 2013-08-25T18:09:16.353 回答
0

根据您对ruakh回答的评论,我自己更喜欢以下方法:

Test.Timers = (function () {
    var this_ = {
        c: null,
        startTimer: function() { this_.c = 0; setTimeout(this_.doWork, 0); },
        doWork: function() {
            this_.c++;
            alert(this_.c);
            setTimeout(this_.doWork, 0);
        }
    };
    return this_;
})();

这样,意思就很清楚了this_this你所要做的就是习惯于创建一个匿名函数并立即调用它的闭包模式。另请注意,我将您的引用固定c为引用this_.c而不是全局变量c

或者,您可以使用.bind()将函数绑定this到特定事物。这是内置在 Chrome 的 V8 中的,至少,也许还有 Firefox:

Test.Timers = {
    c: null,
    startTimer: function() { this.c = 0; setTimeout(this.doWork, 0); },
    doWork: function() {
        this.c++;
        alert(this.c);
        setTimeout(this.doWork, 0);
    }
};
Test.Timers.startTimer = Test.Timers.startTimer.bind(Test.Timers);
Test.Timers.doWork = Test.Timers.doWork.bind(Test.Timers);
于 2013-08-25T19:48:49.563 回答