setTimeout范围问题

Pol*_*yov 28 javascript

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

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

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

zos*_*tay 31

你必须要小心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);
Run Code Online (Sandbox Code Playgroud)

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

  • 为了额外的功劳,请阅读javascript的函数`.call()`和`.apply()`方法,这有助于理解`this`在javascript中是如何工作的,并且当你需要在其他地方定义函数时可以派上用场而不是你传递它的地方.jQuery的`.proxy()`和Prototype的`.bind()`为这个功能提供了整洁的包装器. (3认同)

小智 20

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

你可以缓存外部值,并在里面使用它......

var self = this;

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

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

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

...但是如果你支持遗留实现,你需要添加一个垫片Function.prototype.


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

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

因为有没有结合thisArrow functions.


Kok*_*oko 7

为了防止任何人读到这个,新的javascript语法允许您使用"bind"将范围绑定到函数:

window.setTimeout(this.doSomething.bind(this), 1000);
Run Code Online (Sandbox Code Playgroud)


Jam*_*lin 5

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

var that = this;
...
var timer3 = setTimeout(function() {
    that.alive = true;
    ...
Run Code Online (Sandbox Code Playgroud)

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

var timer3 = setTimeout(() => {
    this.alive = true;
    ...
Run Code Online (Sandbox Code Playgroud)


Sam*_*nov 5

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

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