setTimeout scope issue

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);

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;
    ...

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.

  • MDN Function.prototype.bind patch

...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.


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.

Tags:

Javascript