Javascript setTimeout 范围问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11714397/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
setTimeout scope issue
提问by Polyov
I have a setTimeout defined inside of a function that controls the player's respawn (i am creating a game):
我在控制玩家重生的函数中定义了一个 setTimeout(我正在创建一个游戏):
var player = {
...
death:(function() {
this.alive = false;
Console.log("death!");
var timer3 = setTimeout((function() {
this.alive = true;
Console.log("alive!");
}),3000);
}),
...
}
When it executes, I read in the console, "death!" and 3 seconds later "alive!". However, alive
is never really set back to true, because if i write player.alive
in the console, it returns false
. How come i can see "alive!" but the variable is never set back to true?
当它执行时,我在控制台中读到,“死亡!” 3 秒后“活着!”。但是,alive
从未真正设置回 true,因为如果我player.alive
在控制台中写入,它会返回false
. 我怎么能看到“活着”!但是变量永远不会设置回true?
回答by zostay
You have to be careful with this
. You need to assign your this
in the outer scope to a variable. The this
keyword alwaysrefers to the this
of the current scope, which changes any time you wrap something in function() { ... }
.
你必须小心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);
This should give you better success.
这应该会给你带来更好的成功。
Update 2019-10-09:The original answer is true, but another option is now available for recent versions of JavaScript. Instead of using function
, you can use an arrow function instead, which does not modify this
:
2019 年 10 月 9 日更新:最初的答案是正确的,但现在为最新版本的 JavaScript 提供了另一种选择。除了使用function
,您还可以使用箭头函数,它不会修改this
:
this.alive = false;
Console.log("death!");
var timer3 = setTimeout(() => {
this.alive = true;
Console.log("alive!");
}), 3000);
This is supported from ES6 forward, which is part of all current browsers but IE (of course), I think. If you are using a modern framework to build your project via Babel or whatever, the framework should make sure this works as expected everywhere.
这是从 ES6 向前支持的,我认为这是所有当前浏览器的一部分,但 IE(当然)。如果您使用现代框架通过 Babel 或其他方式构建您的项目,该框架应确保它在任何地方都能按预期工作。
回答by Polyov
It's because this
in the setTimeout
handler is referring to window
, which is presumably not the same value as referenced by this
outside the handler.
这是因为this
在setTimeout
处理程序中引用window
,这可能this
与处理程序外部引用的值不同。
You can cache the outer value, and use it inside...
您可以缓存外部值,并在内部使用它...
var self = this;
var timer3 = setTimeout((function() {
self.alive = true;
Console.log("alive!");
}),3000);
...or you can use ES5 Function.prototype.bind
...
...或者你可以使用 ES5 Function.prototype.bind
...
var timer3 = setTimeout((function() {
this.alive = true;
Console.log("alive!");
}.bind(this)),3000);
...though if you're supporting legacy implementations, you'll need to add a shim to Function.prototype
.
...尽管如果您支持旧版实现,则需要向Function.prototype
.
...or if you're working in an ES6 environment...
...或者如果您在 ES6 环境中工作...
var timer3 = setTimeout(()=>{
this.alive = true;
Console.log("alive!");
},3000);
Because there's no binding of this
in Arrow functions
.
回答by Kokodoko
Just in case anyone reads this, the new javascript syntax allows you to bind a scope to a function with "bind":
以防万一有人读到这里,新的 javascript 语法允许您使用“bind”将作用域绑定到函数:
window.setTimeout(this.doSomething.bind(this), 1000);
回答by Samantha Guergenenov
With ES6 function syntax, the scope for 'this' doesn't change inside setTimeout:
使用 ES6 函数语法,'this' 的作用域不会在 setTimeout 内改变:
var timer3 = setTimeout((() => {
this.alive = true;
console.log("alive!");
}), 3000);
回答by James McLaughlin
Probably because this
isn't preserved in the timeout callback. Try:
可能是因为this
没有保留在超时回调中。尝试:
var that = this;
...
var timer3 = setTimeout(function() {
that.alive = true;
...
Update (2017)- or use a lambda function, which will implicitly capture this
:
更新 (2017)- 或使用 lambda 函数,它将隐式捕获this
:
var timer3 = setTimeout(() => {
this.alive = true;
...