setTimeout with reference to object

The problem

Calling setTimeout or setInterval from an object can be sometimes problematic. The timers are executed outside of your object’s context. You loose reference to your object and can only work with global variables. this suddenly points to window instead.

Solution

I’ve found out that there are plenty of ways to achieve it only after I published this post online. You can use whichever you suits your needs.

  1. using closure
  2. bind(this);
  3. Immediately executing function expression

But first lets see what we’re working with. For all three methods we’ll use the same object, only one function will look different. We’re creating new object of type Person with name Steven and make him say his name after the delay using setTimeout.

// Create new 'class'
function Person(name_)
{
  this.name = name_;
}

// Say whats my name after 2 seconds
// we plug in the reference to `this` person
// with variable named `self`
Person.prototype.whatsMyName = function()
{
  // This one will fail silently with an empty log
  setTimeout(function(){
    console.log(this.name)
  }, 2000);
}

// Define Steven and call him!
var stev = new Person('Steven');
stev.whatsMyName();


Closure

The simplest method will fit in many cases. All variables that are defined in the same block with setTimeout will be available. We could provide the whole context of current object by defining new variable like so:

Person.prototype.whatsMyName = function()
{
  var self = this;
  setTimeout(function(){
    console.log(self.name);
  }, 2000);
}

bind(this);

More elegant method. Here we use bind() to bind the object’s context to the scheduled function.

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

So after 2 seconds, calling this will actually refer to our object. You don’t have to define new variable.

Person.prototype.whatsMyName = function()
{
  setTimeout(function(){
    console.log(this.name)
  }.bind(this), 2000);
}

Immediately executing function expression (IEFE)

May also be known as Self-executing anonymous function.

Person.prototype.whatsMyName = function()
{
  setTimeout((function(param){
    return function() {
      console.log(param);
    }
  })(this), 2000)
}

setTimeout is invoked with 2 parameters, first being IEFEand second, the 2 seconds delay. The function itself also accepts one argument param. This argument can be for example a reference to the object we’re trying to call after 2 seconds, in this case this.