JavaScript: What the hell is this!?

In this post we will cover some JavaScript basics with focus on areas experienced JavaScripters take for granted; but beginners sometimes struggle with.. If you fall somewhere in between then maybe this post will teach you something new!

Consider this function

Then the following examples that use this function in different ways:

Example 1:

Example 2:

Example 3:

What is the output for these?

confused

Some claim to be proficient in JavaScript without knowing this and variable scoping. That would be a lie; just like the cake.

I’ll try to shed some light on the subject with a short introduction followed by concrete examples. If anything it should make you curious and do some more reading.

To cover this, we first need to understand the very basics of variable scope and functions in JavaScript. We will not be going into great detail as we have books for that; but enough to get you going and tickle your curiosity!

Variable Scope:
JavaScript has global and function scope. Put simply, when JavaScript resolves a variable name it will look
1. Within the function that is being executed, or in the parent function(s).
2. The global scope (for example “window” in a browser, or “global” in NodeJS)

If the variable is not found in either of these; it is undefined.

Variables are resolved in the order
1. Current function
2. Outer/parent functions
3. Global

I.e. a variable within the function that is being executed takes precedence over any potential variables in the parent functions with the same name.

The global and function variables are nicely separated despite having the same name. They do not interfere with each other. The function deals with it’s own local variable and leaves the global unmodified.
The “var” keyword is important. When omitted the variable will be referenced through global scope despite being inside a function:

Notice how the global variable got overwritten by the function. This is why it is good practice to stick to local variables unless you really* need to expose the information globally.

Uses of a variable in a function that is not defined there will trigger an outward lookup in the nested function hierarchy, if any.

There are a few other cases of scope we have not covered like closures, but we don’t have the time and space for that in this post.

Functions and properties:
Functions are objects in JavaScript, but with some additional properties that other objects do not have.
They also have the () syntax to run the function. Yep, you use it all the time!

Another important property of functions is that some of the additional properties of functions are other functions.

mind blown

But wait, it’s okay, objects can have functions right, and functions are objects remember? People often forget that functions can be referenced without executing them with (). For example

We just assigned the string property doge to our function. Also we are showing off a bit here; the function property is referenced within the function itself later.

Nothing stops us from assigning functions to our properties instead of strings. In fact this has already been done for us by JavaScript.

call and apply are functions that all JavaScript functions have. There are more as well, but we’ll leave that for another blogpost. The important point is what these call and apply functions can do for us and how they relate to this that you often see used within functions.

call and apply are special and run the calling functions with a specific value of this bound. This is key to understanding how this can mean different things at runtime in identical functions.

The two are similar, the only difference is that call accepts the function parameters in comma-separated syntax while apply accepts an array. The first argument is the value of this in that context.

Syntax of call/apply:

Before we wrap up functions we should have a quick mention of bind as well.
It is similar to call and apply but with one major difference; it does not call the function immediately, it simply returns the function with this rebound to a new value. The function can then be called later.

So… this:
With the basic knowlwedge of how variable scope and functions with their properties work in JavaScript, we can look at this. The source of confusion in countless webapps and many job interviews!

this is a useful reference that is context-dependant. I.e. it’s value changes depending on how the function was executed.

That confuses some developers, as the this keyword can seem random and unpredictable if they have not understood that simple fact; that it is context dependant.
In order to grasp the meaning of this one must consider the context of which it’s function scope was called. Stay with me for some examples.

When called directly, this within function scope refers to the global object (window, or global).

When called as an attribute of an object:

    1. The default; the function parent object specified at the time of calling the function

      That is the behavior considered normal by most developers when they see a function that refers to this. The object that contains the function. Simple!
    2. The explicitly bound value of this through call, apply or another JavaScript function that rebinds the this reference of the function.

That is most often the source of confusion. The calling context above sets this to something else explicitly using the built-in function apply. In this case this is window and not obj.
Your favourite javascript library or built-ins that deals with event-handling actually does this for you (but not with window…) to make your life easier, for example jQuery when assigning a click event like this:

Now the use of call/apply to bind this is hidden to us. I belive that can be one of the reasons why some developers never really seem to “get it”. The feature is used, but they never see the actual line of code that rebinds this with their own eyes. It just works and they are happy.

Events in these libraries usually set the interacting DOM-element as the value of this like the above when calling your event handling function.
Why? Because when something is interacted with that object is usually what we care about in our function! It is convenient, but can be confusing as they do that behind the scenes. It is not magic, jQuery or even basic DOM manipulation simply uses a built-in JavaScript function to rebind this when the function is called; just like in the example above that uses apply()!

So there you have it. The key to understanding this is to realize that it is defined by context.

JavaScript functions have built-in functions that allow you or the author of libraries to decide what this should be for the function at the moment that it is called. Sometimes libraries will do this behind the scenes. In those cases the source code or documentation of the library will help!

Let’s wrap up with our 3 example cases from the beginning:
Example1: The function is called directly, and so this is window within the scope of outer(). And so console.log in outer() prints out “window”. inner() is called directly and logs out “window” as well.

Example2: The function is called using apply. The parameter is the empty object literal “obj”. Now this is obj within the scope of outer(). console.log is then called with this (now set to obj in outer()’s scope) and Object {} is printed.
inner() is called directly and so falls back to having this set to window. window is printed.

Example3: We create a new empty function f. We then bind f to outer() using bind() resulting in a new function. This new function is then called resulting outer() to have this set to f. console.log output in outer() is “function() {}”. inner() is called directly and so falls back to having this set to window. window is printed.

As you see outer() prints out different values of this, but inner() prints window every time. This is to really make a clear point; it is the calling context of the function that is important and in the case of inner() it is the same every time. It is always called in the same way with the same values.

If we wanted inner() to be effected by how outer() was called as well, we would simply call inner with this forwarded from outer.

Next you can take a look at constructor functions. I’ll provide some links for it or write more posts in the future.

Read more from the Software engineering category
SUBSCRIBE TO OUR UPDATES
Menu