Tutorial: Mastering ‘this’ in JavaScript

16 Feb 2018 10:10am, by

One reason the concept of the ‘this’ keyword can be so tricky for a lot of JavaScript programmers — even experienced ones — is because ‘this’ is a slippery little sucker: What ‘this’ refers to depends entirely on context, sometimes in quite perplexing ways.  To make peace with ‘this’ it’s critical to grasp not only how ‘this’ behaves differently in different contexts, but to also understand the contexts themselves — and how to identify them in live code.

Much ink and many tutorial pixels have been spilled over attempts to explain ‘this’. Personally, I have had the most success with the concept of treating ‘this’ as a unique type of variable that changes value depending on the context where it’s used. Variables aren’t so scary, right? We use them all the time. So let’s dig right into ‘this’.

A Bit of Background

In Javascript, functions are objects. Thus, all JavaScript functions have properties and methods, in the same way that objects have properties and methods.

Whenever a function gets executed, it gets assigned its own ‘this’ property—a variable with the value of the object that invokes the function where ‘this’ is used.

In other words, when ‘this’ is used inside a function — let’s call it ourFunction — it acts like a variable that contains the value of the object that invoked ourFunction. Using ‘this’ is more than just a shortcut, though that is certainly a handy aspect. More important is how ‘this’ acts as an identifier: There are times we need this to access methods and properties of the object invoking ourFunction because we don’t always know the name of the invoking object. Sometimes, there is no name to use to refer to the invoking object (like in callbacks, anonymous, or immediately invoked functions).

The invoking object explanation is basically the mirror image of the approach Kyle Simpson takes in book three of his fantastic YDKJS series, THIS & Object Prototypes:

“The most crucial thing to understand is that ‘this’ is not an author-time binding but a runtime binding. Meaning that where ‘this’ points (i.e., in our variable metaphor, the value ‘this’ is assigned to hold) has nothing to do with where a function is declared. Instead, ‘this’ hinges on where the function is called.”

Simpson explains that a function’s ‘this’ binding is determined by its call site, which is absolutely true. But finding the call site — which involves tracing the frequently complex and confusion-making trail of a call stack — can be tricky. Not to mention time-consuming. As a newbie JavaScript coder, I found it much easier to approach ‘this’ from the other direction, i.e., the object invoking the function.  It’s the same destination, ultimately: the object invoking the function is where the call site will inevitably be found. Period. Since objects are generally much easier to identify, particularly in a large codebase, working from a notion of ‘this’ as a variable pointing to the invoking object made my life much, much easier.

‘this’ is actually a binding that is made when a function is invoked, not when it is declared. What ‘this’ references is determined entirely by the call-site where the function is called.

Default ‘this’

A ‘this’ reference ALWAYS refers to — we can even say holds the value of (cough variable cough) — a singular, unique object. Most often ‘this’ is used inside a function or a method. However, it can also be used outside a function in the global scope.

(Lingo explainer for JavaScript n00bs:  “method” is the name for a function contained within an object. “Callbacks” are anonymous functions passed as an argument into another function. Both are still ultimately just functions, though).

In a regular standalone function — or if you are not in a function at all — ‘this’ still must refer back to some invoking object — yet which one, since there is none apparent? But, yup, even these apparently free-range functions have an invoking object: the window object. As in, the actual browser window containing our code, which is represented by an object called ‘Window’. Check it out:

(Note that in strict mode, ‘this’ will hold the value of undefined in global functions — as it will in anonymous functions that are not bound to any object).

‘this’ In Functions Called As Methods

The easiest and most straightforward context for understanding ‘this’ happens when a method is defined and called on the same object. Remember your object dot notation: you access an object’s properties and methods by typing the name of the object, then the dot operator, then the name of whichever of the object’s properties you’re trying to access. (Again, methods are functions declared on an object as properties of that object, but they’re still just functions).

When a method is invoked in conjunction with its defining object, ‘this’ is super easy to track down: look at whatever initializes the property statement. i.e., sits on the left side of the dot notator:

See how it works?  In order to access and invoke ourMethod, we first need to name the object that ourMethod is defined on. That object name, in this context, equals ‘this’. Say it with me: Look for ‘this’ at the left of the dot!

‘this’ In Constructor Functions

Next quick JavaScript review: when a function is being used to create new objects, it is called a constructor function. To call a constructor function, we use the ‘new’ keyword. The giveaway to identifying a constructor function is when the function name starts with a capital letter. That also tells that we need to invoke that particular function using the ‘new’ keyword.

When a constructor function is called, its ‘this’ points to the newly created object, not to the construction function that built it.

Delving a bit into what is happening under the hood helps illustrate why ‘this’ in constructor functions acts as it does. So: whenever a constructor function is called to create a new object, it also, and at the same time, creates a new and matching instance of ‘this’. Simply put, a constructor function’s task is basically just creating a new object with a temporary nickname ‘this’,  and then returning that new object with its own personal ‘this’ assigned to it.

We don’t have to declare ‘this’ because the functionality is built into the ‘new’ keyword — meaning that ‘this’ is automagically created in the background when the constructor function is invoked. The other cool thing that happens is that ‘this’ gets returned along with the new object, also automagically, without us needing to specify a return statement.

To recap: ‘this’ inside of a constructor points to the brand new blank object that the constructor created when invoked. We can then add all the properties — including methods — we like to this swanky new object and get at every single one of them with ‘this’.

Gettin’ Tricky with It

Now things start to get a bit trickier. What happens when we put a function inside the constructor function, and maybe even invoke it?

Here we have our global getThis() function, a constructor function, and a new object created by the constructor function. In this first example are actually calling globally scoped getThis() from inside the constructor function:

getThis() still points to Window, because while it is being invoked inside the Doge() constructor function, the actual getThis() function itself runs in global scope.

However, when we move getThis() inside the Doge constructor function, as a method, its ‘this’ now points to whatever new object is created whenever we run it:

(Above, the console first prints out the new object, dogeSays. Next comes the log statement of getThis() pointing to the new object as its ‘this’, which also points to the new object dogeSays — remember our “left side of the dot” rule???).

What if we invoke the getThis() method inside the constructor function while we are creating a new object?

getThis() still points to the newly created object. Remember higher up when we talked about the placeholder ‘this’ created when a constructor function is run?  Both of these code samples show that placeholder effect in action.

Our takeaway: for methods nested inside constructor functions, ‘this’ is assigned to the newly created object, even though the call site (invocation context) can vary.

This is Not the End of ‘this’

We aren’t done. At this point, you are ready to tackle reasonably straightforward objects and constructor functions and nab their ‘this’ binding with ease. No sweat, now that you know how to first identify the invoking object, and then track down within it the call site determining ‘this’ binding…and look on the left side of the dot.

However, things do get vastly trickier with callbacks — functions passed as arguments into other functions — and so they are going to get their own ‘this’ tutorial. Don’t despair, fellow pilgrims — we will also be learning how to control ‘this’ by setting it to whatever we want it to be. So when you sing ‘this’ confusion to me, even with callbacks, you’ll have a way to extricate and assign the necessary value, .and get on with your life. See you in two weeks!

A newsletter digest of the week’s most important stories & analyses.