JavaScript: What is `this`?!

emiko

emi kojima

Posted on April 30, 2019

JavaScript: What is `this`?!

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 context forest.ocean.animalName()? It's the forest.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!

💖 💪 🙅 🚩
emiko
emi kojima

Posted on April 30, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related