setTimeout范围问题

setTimeout scope issue

本文关键字:问题 范围 setTimeout      更新时间:2024-04-13

我在一个控制玩家重生的函数中定义了一个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。为什么我能看到"活着!",但变量从未设置为true?

您必须小心使用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-09:最初的答案是正确的,但现在可以为最新版本的JavaScript提供另一个选项。您可以使用箭头函数来代替function,该函数不会修改this:

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

这是由ES6-forward支持的,我认为它是除IE(当然)之外的所有当前浏览器的一部分。如果你正在使用一个现代的框架通过Babel或其他什么来构建你的项目,这个框架应该确保它在任何地方都能像预期的那样工作。

这是因为setTimeout处理程序中的this引用的是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添加一个填充程序。

  • MDN Function.prototype.bind补丁

或者如果你在ES6环境中工作。。。

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

因为CCD_ 19中没有CCD_ 18的结合。

为了防止有人读到这篇文章,新的javascript语法允许您使用"bind"将作用域绑定到函数:

window.setTimeout(this.doSomething.bind(this), 1000);

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

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

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

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

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

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