Understanding "this" in JavaScript

Determining the "this" value in JavaScript function in seems to be a constant source of grief for JavaScript developers, so I feel like throwing my hat in the ring with my own attempt at explaining how it works.

It's easier than you think

As it turns out, this, in JavaScript follows a few very simple rules and is quite easy to understand. It just so happens that a) it works very differently than C++, Java, C#, etc and b) many popular libraries, such as jQuery and backbone.js, often manage the this value to make it behave more like the aforementioned languages. These two things together make the behavior of this in JavaScript rather non-obvious. So let's dive in to how this works in pure JavaScript.

First, let's look at plain old functions. Calling a function in JavaScript is simple: the this value is always set to the global object, which is window in browsers and global in Node.js.

function foo() {  
  console.log(this === window);
}
foo(); // prints "true"  

But what if the function is part of an object? As it turns out, the this value is determined by how the function is called, and nothing else. If the function is being directly referenced as a property on an object, then the this value is that object, otherwise it's global. To put it another way, if you have foo.bar or foo["bar"], then this is set to foo.

var foo = {  
  bar: function () {
    console.log(this === window);
    console.log(this === foo);
  }
}
foo.bar(); // prints "false" then "true"  

OK, seems simple enough, but what if that function is referenced indirectly? Since the this value is determined only by how it was called, that means it doesn't actually matter if it's a part of an object or not! If we assign the function to a variable and call it that way, then JavaScript follows the rules for simple functions and sets this to the global object:

var foo = {  
  bar: function () {
    console.log(this === window);
    console.log(this === foo);
  }
}
var bar = foo.bar;  
bar(); // prints "true" then "false"  
foo.bar(); // prints "false" then "true"  

That's it. That's how this works. There really isn't anything else to it, unless you manually change the this value yourself.

Changing the value of "this"

There are three methods that all functions have that allow you to change the this value: call, apply, and bind. Call and apply are more or less the same, they just have a slightly different signature. The first argument to both methods is the value that you want for this, and after that is the arguments to the function.

var x = {};  
function foo (y, z) {  
  console.log(this === x);
  console.log(y + z);
}
foo.call(x, 5, 5); // prints "true" then "10"  
foo.apply(x, [ 5, 5 ]); // prints "true" then "10"  

They each have their uses, so pick whichever one fits your needs best. One cool thing you can do with apply is to forward arguments to another function without needing to know anything about them,  which is really handy in prototypal inheritance:

function x() {}  
x.prototype.hi = function (a, b) {  
  console.log(a + b);
}

function y() {}  
y.prototype = new x();  
y.prototype.hi = function () {  
  x.prototype.hi.apply(this, arguments)
}

var z = new y();  
z.hi(5, 5); // prints "10"  

The third function, bind, works a little differently. When you call bind, it doesn't actually call the function, but instead returns a new function that will have its this value set to whatever you supplied to bind so that you can call it later:

var x = {};  
function foo() {  
  console.log(this === x);
}

var boundFoo = foo.bind(x);  
foo(); // prints "false"  
boundFoo(); // prints "true"  

Note: bind is in ECMAScript 5 only, so it doesn't work in IE8 and older, but fortunately underscore.js has an implementation that works in older browsers (_.bind).

Callbacks

The way that this works becomes really annoying when you're dealing with callbacks because the this value is set to the global object unless the underlying event firing mechanism changes it for you.

var x = {  
  foo: function () {
    console.log(this === x);
    console.log(this === window);
    setTimeout(function () {
      console.log(this === x);
      console.log(this === window);
    }, 1000);
  }
};
x.foo(); // prints "true" then "false", then about a second later prints "false" then "true"  

A lot of people do something like:

var self = this;  

and then reference self in their callbacks. It works, but feels a little hacky. Instead, you can also do:

var x = {  
  foo: function () {
    console.log(this === x);
    console.log(this === window);
    setTimeout(function () {
      console.log(this === x);
      console.log(this === window);
    }.bind(this), 1000);
  }
};
x.foo(); // prints "true" then "false", then about a second later prints "true" then "false"  

Now the this value is what we want it to be for our callback. It's worth point out though that aliasing this to self does have one nice advantage: self can be minified to a single character, whereas this will always be 4 characters since it's a keyword. If code size is critical, then aliasing this to self almost always results in slightly smaller code size.

One last note about libraries and callbacks: many libraries use apply and call to set the this value to something more useful than the global object, so make sure you read the documentation to make sure that you are getting the this value you expect. If you want a this value other than what the library sets, just use .bind or _.bind. In the case of nested applys, calls, or binds, the last one wins, so you can always set it to whatever you want.

I hope this helps demystify how this works in JavaScript!