Javascript 设置超时作用域问题

Javascript 设置超时作用域问题,javascript,Javascript,我在控制玩家重生的函数中定义了一个setTimeout(我正在创建一个游戏): 当它执行时,我在控制台中读到“死亡”,3秒钟后读到“活着!”。但是,alive永远不会真正设置回true,因为如果我在控制台中写入player.alive,它将返回false。为什么我可以看到“alive!”但变量从未设置回true?您必须小心使用此。您需要将外部范围中的this分配给变量。this关键字总是指当前作用域的this,当您在function(){…}中包装某些内容时,它会发生更改 var thing =

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


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

您必须小心使用
。您需要将外部范围中的
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。您可以使用箭头函数代替
函数
,该函数不会修改

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

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

这是因为
setTimeout
处理程序中的
这个
指的是
窗口
,它可能与处理程序外部的
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);

因为有.

可能是因为
这个
没有保存在超时回调中。尝试:

var that = this;
...
var timer3 = setTimeout(function() {
    that.alive = true;
    ...
更新(2017)-或使用lambda函数,该函数将隐式捕获

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

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


使用ES6函数语法,“this”的作用域在setTimeout内不会更改:

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

在这个作用域中,this是传递给setTimeout的匿名函数,您需要将this分配给其他变量,然后检查它是否有额外的积分,阅读javascript的函数
.call()
.apply()
方法,这些方法有助于理解
this
在javascript中的工作原理,当您需要在传递函数的地方以外的其他地方定义函数时,它可以派上用场。jQuery的
.proxy()
和Prototype的
.bind()
为该功能提供了简洁的包装。除@BrianMortenson所说的之外,JS还有自己的功能(在1.8.5版中引入,因此在旧版IE中不受支持)。实际上,MDN页面上的一个示例是与
setTimeout()
一起使用的。除@nnnnnn所说的之外,如果您使用的是ES6,则可以使用带箭头的函数。()=>setTimeout(()=>this.alive=true,3000)不幸的是,像这样直接绑定到函数似乎不起作用(至少在Chrome60中不起作用)。似乎您必须首先通过匿名函数运行它,如上面的“community wiki”ES5示例中所示。在我看来,不应该再使用
that=this
解决方案,因为它只会增加由
this
关键字引起的混乱。最好使用箭头符号
setInterval(()=>{})
或使用
bind()
来修复javascript的作用域问题。@Kokodoko我同意!这一点在2012年得到了回答。我会更新答案。