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
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.”
‘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.
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.
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
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!