setTimeout范围问题

时间:2012-07-30 01:18:10

标签: javascript

我在一个控制玩家重生的函数内部定义了一个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。为什么我能看到"活着!"但变量永远不会变回真?

5 个答案:

答案 0 :(得分:28)

你必须小心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);

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

答案 1 :(得分:16)

这是因为this处理程序中的setTimeout指的是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);

因为有no binding of this in Arrow functions

答案 2 :(得分:7)

万一有人读到这个,新的javascript语法允许你用" bind"

将一个范围绑定到一个函数
window.setTimeout(this.doSomething.bind(this), 1000);

答案 3 :(得分:5)

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

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

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

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

答案 4 :(得分:4)

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

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