What is this?!

This post discusses the this keyword, what it represents, how it can catch you out and how to avoid those problems. It also introduces the functions call and apply from the Function prototype.

Let's start with a definition -

The value of this is determined at the point at which the function is invoked, and is set to the object on which the function is invoked

And expressed as pseudo code -

obj.func() // within the function func "this == obj"

In many ways it's easier to think of this as an argument to the function, rather than as something that is associated with the function itself, as it would be in Java/C#/etc.. If you're more used to a Java/C# here's an example showing everything working the way you'd expect -

var obj = {
    func : function (expected) {
        return expected == this;
    }
};
obj.func(obj); // true

However, here are two examples showing things working in a way you might not expect -

// a common problem
var fn = obj.func;
fn(obj); // false
fn(window); // true

// a not-so-common problem
var obj2 = {
    fn : obj.func
};
obj2.fn(obj); // false
obj2.fn(obj2); // true

The problem with the first example is that the function it is not invoked on our object or indeed any object. Therefore within the function this defaults to the global object, which happens to be the window object in browsers.

In the second example, we've created a reference to our function on a new object (obj2) and invoked the function on it. Therefore within the function this is a reference to obj2.

We can easily re-write both of the problematic examples so that they function correctly by using a bit of indirection (and closure) -

// a common problem rewritten
var fn = function (arg) { 
    return obj.func(arg); 
};
fn(obj); // true

// a not-so-common problem rewritten
var obj2 = {
    fn : function (arg) { 
        return obj.func(arg); 
    }
};
obj2.fn(obj); // true

And that's all there is to it, the rest of the post goes on to describe the last pieces of the puzzle, however for most development you won't need to know anything else.

As the caller of a function you can also have explicit control over the value of this with the call and apply functions e.g.

var fn = obj.func;
fn.call(obj, obj); // true
fn.apply(obj, [obj]); // true

(The difference between call and apply is how they deal with the arguments following the this value. Call expects a number of further arguments to be passed to the function. Whereas apply expects a second argument which is an array of the arguments to be passed to the function.)

Some libraries (e.g. Prototype, MooTools, DoJo, etc.) take advantage of these functions and allow you to "bind" the value of this to a function. The libraries normally provide a new function on the Function prototype e.g.

var fn = obj.func.bind(obj);
fn(obj); // true

A simple implementation of "bind" could return a new function that invokes the original function using either the call or apply to set the value of this e.g.

Function.prototype.bind = function (ctx) {
    var fn = this;
    return function (arg) {
        return fn.call(ctx, arg);
    }
};

(N.B. this is only a very basic implementation - it doesn't have support e.g. for passing on n arguments, which you'd expect to find in a library method.)

Personally I prefer not to use "bind" functions, as I think they hide what is happening from less experienced developers in a way that leads them to develop JavaScript in a Java/C# way. Instead I'd rather they see what is actually happening, and then at least they have a chance of fully embracing the language and it's unique features.

Hopefully this post has cleared things up a bit, if you think it could be clearer let me know and I'll do my best to correct it.

Cheers, Chris

blog comments powered by Disqus