JavaScript: What is `this`?!
emi kojima
Posted on April 30, 2019
JavaScript: What is this
?!
*As you read this blog post, it might be helpful to open up your Developer Console (Windows: Ctrl + Shift + J or Mac: Cmd + Option + J) and code along with me. *
Overview: this
In Javascript, this
is all about context and this can be very confusing.
What I mean ☝ is that the value of this
is dependent on its execution context (ie: where this
is being called) - meaning that depending on where this
is being executed/called, what this
references will change. That's what can make this
so useful. In order to understand the value of this
we need to look to the call site (execution context).
Try pasting this code in your console:
console.log(this);
You should see something like this after you hit the return key :
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
which means that this
refers to the global window object. This makes sense becuase we called this
from the console (its execution context), which by default refers to the global window object.
In a simple function call, the execution context for this
refers to the global (window) object by default.
Here's an example of that:
function hey () {
console.log("Hey, I'm a simple function call");
console.log(this === window);
}
hey()
You shoud see this in your console:
Hey, I'm a simple function call
true
Here, in a simple funcion call, this === window
, which is why the console.log came back as true
.
Now put this into your console:
var animal = {
cat : function() {
console.log(this)
console.log(this.sound)
},
sound: "hrrrrmph"
}
animal.cat()
You should see something like this in your console:
cat: ƒ, sound: "hrrrrmph"
followed by:
hrrrrmph
in the above context, this
refers to the animal object and this.sound
becomes the animal object's sound value ("hrrrrmph").
Ok, lets' take it up another level!
var animal = {
bear: function () {
var sound = "ROARRRR"
this.cat()
},
cat : function() {
console.log(this.sound)
},
sound: "hrrrrmph"
}
animal.bear()
What do you think will happen when we run the above code?
Here, by calling animal.bear()
we call this.cat()
which logs in our console "hrrrrmph". That's becuase the execution context for this in this.cat()
is animal. So calling animal.bear()
calls animal.cat()
which console.logs(this.sound)
.
What if we moved the var sound = "ROARRRR" from the bear to cat?
var animal = {
bear: function () {
this.cat()
},
cat : function() {
var sound = "ROARRRR"
console.log(this.sound)
},
sound: "hrrrrmph"
}
animal.bear()
Did you guess that we would still get "hrrrrmph"?!
I didn't! But like I said before,THIS is complicated! Let's remember the other thing I said before. this
is all about context (execution context to be exact). Let's walk through it together.
When animal.bear() is being called, the this
in this.cat()
is the animal object. So the this
in the console.log(this.sound)
is the animal object! This is where the call was executed, which means that we are console logging animal.sound
.
What about this code below? Try to figure out the execution context of this
.
var animal = {
bear: function () {
this.cat()
},
cat : function() {
var sound = "ROARRRR"
console.log(this.sound)
},
sound: "hrrrrmph"
}
animal.cat()
this
still refers to the animal object! So, we still get hrrrrmph
OK, let's try to get deeper into this
:
var animal = 'Cat'
var forest = {
animal: 'Bear',
ocean: {
animal: 'Pelican',
animalName: function() {
return this.animal
}
}
}
forest.ocean.animalName()
OK, BEFORE we go on to see what the code above will return, let's talk about the scope of each animal.
- Cat 🐱 belongs to the GLOBAL 🌐 window .
- Bear 🐻 belongs to the FOREST 🌲 scope.
-
Pelican 🐦 belongs to OCEAN 🌊 (forest.ocean)
Now back to the code.
What do you think
this
refers to in the contextforest.ocean.animalName()
? It's theforest.ocean
object! So, this.animal (which is the same as forest.ocean.animal) returns "Pelican" because the Pelican belongs to the OCEAN. GOOD. What if we added this to the code to the console:
var animalName = forest.ocean.animalName
making animalName
a function that returns this.animal
Now, run this code in your console:
animalName()
what do you think we would see returned? What is the execution context of this
? If you said global, you are right! Running the code animalName()
is equivalent to running this.animal, and since we are executing this code from the global window, it's just like calling window.animal, which is "Cat"!
How would I be able to use the animalName() (which returns this.animal
) to return "Bear"?
📞 The call
That's where the .call() function comes in. Here's what the W3Shool says about the .call():
**With call(), an object can use a method belonging to another object. **
Sounds simple enough. Let's code it in! Since we know from ☝ that Bears belong to FOREST, let's pass forest in to the .call function.
animalName.call(forest)
And TA-DAAA, we get "Bear"
What would we get if we executed this code:
animalName.call(window)
That's right, we'd get "Cat".
Now that we have a handle on this
, let's talk about when using this
won't work for us.
The ➡️ arrow function and this
Arrow functions are a more syntactically concise way of writing function expressions and some argue are easier to read. You can read more about arrow functions here and here. But here's the briefest of overviews:
A regular function is written like this:
function animalName () {
return this.animal
}
Here's how the same function looks with an arrow function:
arrowAnimalName => () => this.animal
I like them both, but I'm a gemini, so that's to be expected.
BUT why am I bringing up arrow functions in relation to this
, you ask.
It's because in arrow functions this
is lexically bound - meaning that this
never changes 😱.
Cynthia Lee on FreeCodeCamp breaks it down like this:
**In classic function expressions, the this keyword is bound to different values based on the context in which it is called. With arrow functions however, this is lexically bound. It means that it uses this from the code that contains the arrow function.
**
Which means that we can't use .call(), or .apply() or .bind() with arrow functions because this
is lexically bound to the where the arrow function is executed.
So if we run
arrowAnimalName.call(forest)
we will get "Cat" because the this
is lexically bound to the Global window where we defined this arrow function.
All of this
can get really confusing and maybe feel overwhelming. But you know what? We will always have console.log(this)
and debugger
to help us find out what this
really is, and THAT leaves me feeling pretty 🌈 .
Thanks for reading!
Posted on April 30, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.