The this
keyword is a notorious roadblock on the path to grasping JavaScript. Just referring to it sounds funny – “the this” – the what now? Understanding this
is key to becoming an adept JS programmer, though. So let’s break it down.
Prereqs for understanding ‘this’
The this
keyword is primarily used in the context of Object Oriented Programming, which is a whole thing in and of itself. If you’re not yet familiar with what objects are and the general gist of OOP, this (pun intended) might be a good time to check out the link and orient yourself before proceeding.
In order to fully understand all the possible meanings of this
, you’ll also need to know what events, object methods, and scope are, and to really really get it, what strict mode is. I’m actually going to save strict mode for another post, so for now just know that it’s a thing, and changes what this
can mean.
Lastly, you need to keep in mind that this
is a keyword, not a variable. You can’t change the meaning of this
in a direct way like you would a variable. Its meaning is all dependent on how, aka the context in which it’s used.
The definition
In JavaScript, in non-strict mode, the this
keyword refers to an object. Sounds simple, right?
The tricky part is understanding which object this
refers to, because which object this
refers to all depends on how this
is being invoked.
So, let’s take a look at the different ways this
can be invoked, and we’ll identify which objects it refers to based on each context. After we run through the different contexts, we’ll look at a series of questions you can ask yourself to narrow down which context applies.
All the Objects
- In an object method,
this
refers to the object the method belongs to. - Alone, in the global scope,
this
refers to the global object. - In a function,
this
refers to the global object. - In an event,
this
refers to the DOM element that received the event. - Methods like
bind()
,call()
, andapply()
can makethis
refer to any object. - *In strict mode,
this
can be any value. Woah! Don’t worry about strict mode for now, though. Just know that it’s the only context in whichthis
doesn’t stick to the basic rule of always referring to an object.
Okay, that’s a lot, and far too concise for practical understanding, so let’s dig in to each context a little more.
In an Object Method
Whenever this
is used in a method that’s defined in an object, it refers to that object.
Take the classic example of defining a person
object literal:
const person = {
firstName: "Jane",
lastName: "Doe",
fullName() {
return this.firstName + " " + this.lastName;
}
};
person.fullName(); // returns Jane Doe
In the above, fullName()
is a method of the person
object. Because this
is being used inside of fullName()
, we know it refers to person
, and any properties we append this
with will be properties of person
.
*An important note about object methods and this
– the method has to be defined either using the function
keyword, or the concise syntax used above. If an =>
arrow function is used, the value of this
is not bound to the containing object.
Alone
When this
is used alone, meaning hangin’ out there in the global scope, outside of any function, object or method, it refers to the global object. This is rare, but good to know about.
this.x = 2; // sets x property of global object
console.log(x) // prints 2
Now, what the global object actually is depends on what environment we’re in. In a browser environment, the global object is window
. In an environment like Node.js, the global object just means the global scope, which we shouldn’t be polluting in the first place.
In a Global Function (non-strict mode)
In similar fashion to when this
is used alone in the global scope, when this
is in a function in the global scope, the global object is also the default binding. That’s because all global variables, including global functions, are properties of an unnamed global object.
function f(x) {
this.y = x + 1;
}
f(2); // f is called as a global function
console.log(y); // prints 3
In the above, the f()
function is in the global scope, so this.y
sets a y property of the global object with a value equal to whatever argument is passed to f()
plus 1.
*Remember that invoking a function with the new
keyword is not the same as defining a global function. Functions invoked with new
create new objects, so any use of this
inside of them would refer to the object being created, just like with our first example on object methods.
In Events
In event handlers, this
refers to the DOM element that receives the event.
Here’s an example of a button with a click event:
<button onclick="this.style.display='none'">
Click to make me disappear
</button>
The <button>
element is what receives the click event, so when the button gets clicked, this
is referencing the <button>
element, and sets its display
property to none
.
In apply(), call(), and bind()
The predefined JavaScript methods apply()
, call()
, and bind()
let you explicitly define the object you want to use as the value of this
. Doing so is called explicit function binding.
Let’s try an example with the call()
method. Here’s the syntax for call()
:
function.call(thisArg, arg1, arg2, ...)
thisArg
is the object we want to makethis
refer to.arg1
,arg2
, and so on are individual arguments that we want to pass to the function we’re invoking.
Now, here we have a greet()
function that uses the name
property of the object to which this
refers. It takes a message
parameter and logs a greeting using that message and a name value. We’re going to use call()
to invoke greet()
and explicitly set the object that we want the name
property of.
function greet(message) {
console.log(message + ', ' + this.name);
}
const person1 = { name: 'Jane' };
const person2 = { name: 'John' };
// use call to set 'this' to the person object
greet.call(person1, 'Hello'); // Hello, Jane
greet.call(person2, 'Hey'); // Hey, John
When call()
invokes greet()
the first time, it specifies person1
as the context, and passes ‘Hello’ as the message
argument. So, when greet()
is executed, this
refers to the person1
object where the name
value is Jane.
When call()
invokes greet()
again, it’s in the context of person2
, and uses a different message. So we get “Hey, John” logged to the console.
How do I know?
If you’re not totally sure which object this
refers to because more than one context might be influencing its meaning, we can use the following order of precedence:
bind()
apply()
andcall()
- Object method
- Global scope
So, you can ask yourself the following questions in order, and the first one you answer “yes” to will tell you what context takes precedence:
- Is
this
in a function being invoked withbind()
? - Is
this
in a function being invoked withapply()
orcall()
? - Is
this
in an object method? - Is
this
in a function in the global scope?
And there you have it! Err… there you have this
!