Reputation: 2311
I have a setTimeout defined inside of a function that controls the player's respawn (i am creating a game):
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?
Upvotes: 36
Views: 48915
Reputation: 3995
You have to be careful with this
. You need to assign your this
in the outer scope to a variable. The this
keyword always refers to the this
of the current scope, which changes any time you wrap something in 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
:
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.
Upvotes: 50
Reputation: 51
With ES6 function syntax, the scope for 'this' doesn't change inside setTimeout:
var timer3 = setTimeout((() => {
this.alive = true;
console.log("alive!");
}), 3000);
Upvotes: 5
Reputation: 16718
Probably because this
isn't preserved in the timeout callback. Try:
var that = this;
...
var timer3 = setTimeout(function() {
that.alive = true;
...
Update (2017) - or use a lambda function, which will implicitly capture this
:
var timer3 = setTimeout(() => {
this.alive = true;
...
Upvotes: 5
Reputation:
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.
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
...
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
.
...or if you're working in an ES6 environment...
var timer3 = setTimeout(()=>{
this.alive = true;
Console.log("alive!");
},3000);
Because there's no binding of this
in Arrow functions
.
Upvotes: 25
Reputation: 28128
Just in case anyone reads this, the new javascript syntax allows you to bind a scope to a function with "bind":
window.setTimeout(this.doSomething.bind(this), 1000);
Upvotes: 10