blog tumblog github @santosh79 resume
September 15th 2012

Understanding the this reference in Javascript

The this reference in Javascript is probably one of the most confusing scoping concepts for people coming new to the language. Understanding, the this reference lets you unlock the mysteries of Object Oriented Javascript and gain a better/more intuitive understanding of how the object model is structured.

Explicitly setting the this reference

Here’s a little code to get us going

function setVar(arg) {
  this.var = arg;
}
var obj = Object.create(null);
obj.setVar = setVar;
obj.setVar('hello');
console.log(obj.var); // => 'hello'

What’s going on here?

- We are declaring a function called "setVar" that sets the "var" property of whatever the "this" reference is pointing to, to the argument it receives
- We then construct an object called "obj", assign it's "setVar" property to the setVar function
- Finally we call the setVar function *via* the obj object

Executing this code, you’ll see that the obj object does now have a var property set to ‘hello’. Even though, no where in our code we are doing:

obj.var = 'hello';

How is this? When you call object.method() the this reference is set to object within the confines of method. In the above case, since we called obj.setVar the this reference was set to point to obj within the confines of the setVar method. And since, setVar adds a property called var to whatever it’s this is, obj was gifted with the var property.

Setting the this reference using “call” or “apply”

Javascript let’s you specify what you would like the this reference to be when calling a function, by using either the call() or apply() functions. The format of call() is:

SomeFunction.call(the_this_object, *arguments)

Rewriting the previous example to use call()

function setVar(arg) {
  this.var = 'hello';
}
var obj = Object.create(null);
setVar.call(obj, 'hello');
console.log(obj.var); // => 'hello'

As you can see, this feels a little more flexible and is sometimes better than the object.method() approach. The apply() function is identical to call() with the only difference between that the last argument is an array instead of your arguments being laid out comma seperated. If we were to use apply() instead it would be:

setVar.apply(obj, ['hello']);

Capturing the this reference

You might often see code that does:

var that = this;
....
Some code follows
        ....

And you might wonder why are they doing this. Inside every function call, the this reference is reset. So for example:

function outer() {
  this.foo = 'blah';
  function inner() {
    console.log(this.foo);
  }
  inner();
}
var obj = Object.create(null);
outer.call(obj);

Running this, results in undefined being logged. Why is that? The this reference in outer is set to obj since we are explicitly doing this by the call() function. However, in inner() the this reference points to a different object, which is why logging the foo property of this in inner() resulted in undefined.

How do we fix this? One way is to capture the this reference and use it.

function outer() {
  var that = this;
  that.foo = 'blah';
  function inner() {
    console.log(that.foo);
  }
  inner();
}
var obj = Object.create(null);
outer.call(obj);

Another way, would’ve been to call inner() using the call() function passing the this of outer to it. Personally, I think this is more readable.

Using the bind function

Javascript also let’s you bind the this reference to a function, so all future invocations of that function will use the object you had initially bound the function to. This is useful when you don’t want to keep remembering to use the call() function. An example of bind()

function setFoo() {
  this.foo = 'bar';
}
var obj = Object.create(null);
var boundSetFoo = setFoo.bind(obj);
boundSetFoo();
console.log(obj.foo); // 'bar'

Here, we are creating a bounded reference to the setFoo() function called boundSetFoo with the object obj being the this. This way of capturing this is particularly helpful when working with events and event handlers.

function eventHandler(evt) {
  if(!this.eventsReceived) {
    this.eventsReceived = [];
  }
  this.eventsReceived.push(evt);
  console.log('event is %s', evt);
}
var evtEmitter = Object.create(events.EventEmitter.prototype);

var obj = Object.create(null);
evtEmitter.on('some_event', eventHandler.bind(obj));

var someOtherObj = Object.create(null);
evtEmitter.on('some_event', eventHandler.bind(someOtherObj));

obj.emit('some_event', 'hi there');

Here we have two objects obj and someOtherObj both of which have subscribed to the some_event event on the evtEmitter object. Notice, how we reuse the eventHandler function but tweak it to bind to the right object just when we need it to. Neat, heh?

TL;DR

Javascript is super malleable, letting you bend it to your will. This malleability lets you come up with incredibly elegant solutions for seemingly intractable problems. But this malleability means, it’s pretty easy to write poor code too.

blog comments powered by Disqus