33

我在控制玩家重生的函数内部定义了一个 setTimeout(我正在创建游戏):

var player = {
    ...
    death:(function() {
        this.alive = false;
        Console.log("death!");
        var timer3 = setTimeout((function() {
            this.alive = true;
            Console.log("alive!");
        }),3000);
    }),
    ...
}

当它执行时,我在控制台中读到“死亡!” 3 秒后“活着!”。但是,alive永远不会真正设置回 true,因为如果我player.alive在控制台中写入,它会返回false. 我怎么能看到“活着”!但变量永远不会设置回真?

4

5 回答 5

46

你必须小心this。您需要将this外部范围内的变量分配给变量。this关键字总是指当前作用域的this,每当你在function() { ... }.

var thing = this;
thing.alive = false;
Console.log("death!");
var timer3 = setTimeout((function() {
    thing.alive = true;
    Console.log("alive!");
}),3000);

这应该会给你带来更好的成功。

2019 年 10 月 9 日更新:最初的答案是正确的,但现在可以为最新版本的 JavaScript 提供另一种选择。除了使用function,您可以使用箭头函数,它不会修改this

this.alive = false;
Console.log("death!");
var timer3 = setTimeout(() => {
    this.alive = true;
    Console.log("alive!");
}), 3000);

这是从 ES6 开始支持的,我认为它是所有当前浏览器的一部分,但 IE(当然)。如果您使用现代框架通过 Babel 或其他方式构建您的项目,那么该框架应该确保它在任何地方都能按预期工作。

于 2012-07-30T01:21:13.207 回答
22

这是因为thissetTimeout处理程序中引用window,这可能this与处理程序外部引用的值不同。

您可以缓存外部值,并在内部使用它...

var self = this;

var timer3 = setTimeout((function() {
    self.alive = true;
    Console.log("alive!");
}),3000);

...或者您可以使用 ES5 Function.prototype.bind...

var timer3 = setTimeout((function() {
    this.alive = true;
    Console.log("alive!");
}.bind(this)),3000);

...尽管如果您支持旧版实现,则需要在Function.prototype.


...或者如果您在 ES6 环境中工作...

var timer3 = setTimeout(()=>{
    this.alive = true;
    Console.log("alive!");
},3000);

因为in没有绑定thisArrow functions

于 2012-07-30T01:21:31.407 回答
10

以防万一有人读到这个,新的 javascript 语法允许您使用“绑定”将范围绑定到函数:

window.setTimeout(this.doSomething.bind(this), 1000);
于 2016-02-22T14:45:56.883 回答
5

可能是因为this超时回调中没有保留。尝试:

var that = this;
...
var timer3 = setTimeout(function() {
    that.alive = true;
    ...

更新(2017) -或使用 lambda 函数,它将隐式捕获this

var timer3 = setTimeout(() => {
    this.alive = true;
    ...
于 2012-07-30T01:21:39.120 回答
5

使用 ES6 函数语法,'this' 的范围在 setTimeout 内不会改变:

var timer3 = setTimeout((() => {
    this.alive = true;
    console.log("alive!");
}), 3000);
于 2017-08-03T21:20:21.663 回答