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