this & functions

Javascript's this is a confusing paradigm for newcomers to the language as well as some more seasoned developers. Admittedly, it was completely strange to me for a fair amount of time despite having read a little bit about it. Without a full understanding of its genesis it can seemingly take on random values and (in the case of strict mode) never have a value to begin with. The thing that really helped clarify its behavior, to me, was a decent understanding of how functions behave in Javascript.

The first thing to show in regards to this is that its creation is not handled at all like it is in Java. In Java, this always refers to the current object wherein this is used. Not so in JS. In JS, this is implicitly injected into the function from the context with which that function was called. For example, if we create a function...

function sampleFunction() {
  console.log('this',this);
}

and later call on that function, some might be inclined to think that the console will simply print this undefined.

Again, not so (note: we're discounting the possibility of strict mode here). What will print to the console is a massive object, which happens to be the global context. Interesting. To further the point, let's do something else.

var x = 2;
function sampleFunction() {
    console.log('this',this);
}
sampleFunction();

If you inspect this object on the console, you'll see x listed (on my console output it was way at the bottom). That's really interesting. And this is where this becomes dangerous...

Noting the example above and extending it we see why so many people can get frustrated with this. What happens if we put another x variable inside the sampleFunction? Let's check 'er out...

var x = 2;
function sampleFunction() {
    var x = 'cat';
    console.log('this.x', this.x);
}
sampleFunction();

So now, we inspect our console output and, wait a minute, this.x is printing 2. That's funny. In Java, it would have printed 'cat'; ignoring, of course, the multiple declarations of x, which would have Java throwing a compile-time error. So that result is a little unexpected, or at least would be for someone that didn't understand function behavior in JS. When you realize that the this object is being passed implicitly as a contextually-based object into the function the result of console.logging x makes much more sense. Let's draw it out a little more explicitly:

var x = 2;
var this = {
    /* Pretend everything in this object's surrounding
    scope is an attribute here, including 'x'
    */
}

// our 'this' object is passed in here...
function sampleFunction( this ) {
    var x = 'cat';
    /*
    Here 'this' is { x: 2, ...every other object/value in the
    outer (in this case the global/window) scope }
    */
    console.log('this',this);
}

sampleFunction();

This code won't actually work because 'this' is a keyword, but it shows what is going on behind the scenes. The 'this' object is being created (implicitly) by the Javascript compiler then being silently passed into our sampleFunction function.* Okay, so it's making a little more sense right now, but there's still more to be explained. What happens if we do this...

var x = 2;

function sample() {
    var x = 'cat';
    console.log('this',this.x);
}

function outerSample() {
    var x = 'outer cat';
    sample();
}

outerSample();

What would be in our console now? The answer is still 2. You could nest this as much as you wanted into a hundred other functions and you'd still end up with 2 in your console. Why? Well, this is completely dependent on how the function is invoked, in which there are four ways:

  • The 'normal' way (as a standard function like we've been doing)
  • As a method of an object
  • Using the new keyword
  • Using apply or call (I won't be discussing this in this article.)

We've already seen how this functions when its function is invoked in the 'normal' manner. Let's see how it functions in other scenarios.

Invocation as a method and using the new keyword

Functions attached to an object behave in the much-more recognized, object oriented way, i.e. the 'Java way'. The function context which is passed to the method (function context is what this describes) is born within the object that holds the method as an attribute. This is more easily stated as an example, so let's do that.

var job = 'Unemployed';

var me = {
    job: 'Software Developer',
    getJob: function() {
        return this.job;
    }
}

console.log(me.getJob());

What will be printed to our console? Well, remembering what was stated above about which context (this) was being passed into our getJob function, we see that 'Software Developer' was printed happily to the console. Thankfully... I mean, I don't want to be unemployed. Will this work also work if instead of defining the function within the object we just reference a global function from the object? Let's see...

var job = 'Unemployed';

function getJobOuter() {
    return this.job;
}

var me = {
    job: 'Software Developer',
    getJob: getJobOuter
}

console.log(me.getJob());

and, after printing, we see that 'Software Developer' is still being printed to our console. Excellent, the object is still asserting its context within the function. When you call a method off of an object remember that object is injecting its context into the function. Visually, that's...

someObject.someFunction(); // someObject -> (injects context into) -> someFunction

The new keyword is fantastic for dynamically creating an object and having functions assigned to that object reference that object's context. It works similarly to method invocation, but rather than dealing with object literals, we're dealing with globally-defined functions. Let's check out an example...

var job = 'Unemployed';

function Me() {
    this.job = 'Software Developer';
    this.getJob = function() {
        return this.job;
    };
}

var me = new Me();
console.log(me.getJob());

Now, remember last time we dealt with a globally-defined function (one that has the global this injected into it) no matter what we did we couldn't reference anything but attributes of the global object. In this console output we see that the newly instantiated object (courtesy of the new keyword) is referencing its own context! Fantastic.

I should note that creating objects with the new keyword does come with some drawbacks, which I plan to address in a future article. But, for 99% of people out there it's nothing to stress-out about.

With any luck this illuminated how easy it is to predict which this you'll be dealing with when you're messing around in JavaScript. In a future article I'll be discussing apply and call, which are pretty straightforward once you have the above ideas down.

Thanks for reading!

*Note: There is also another implicitly-passed object here called 'arguments', but that's another discussion altogether. We'll ignore it for now.