'this'
is one of the most important concepts in JavaScript. It's part of the basics and the sooner you get comfortable with it the easier your coding life will be :)
Make sure you understand the use of 'this' by reading this post.
First, the simple 5 yo explanation:
The use of
'this'
in programming is like what you do in plain English. For example, when you say "I got a job! This is great!". We know 'this' is referring to the fact you got the job. In other words, 'this' gives context to the second sentence.
--5 yo
So, to understand 'this'
, you need to know what context is.
Context explained
Context is related to objects. It refers to the object a method or property belongs to. Your code starts running in a global context, which in your browser is the window
(in Node, the global object is called global
). Look at the example below:
var name ='Beyonce'
console.log(this.name) // Beyonce
console.log(window.name) // Beyonce
In the example, 'this'
equals window
because I ran it on my browser, where the global object is the window. So, window.name ==="Ash" . So far, the context is window. Ok.
Now, the context changes during your code execution. Whenever an object's method is called, 'this'
is set to the object the method was called on.
See the example below. Both lines 4 and 10 are identical but they log different results according to the value of 'this'
.
var name = 'Beyonce'
function sayMyName(){
console.log(`Your name is ${this.name}.`) // 'this' is window
}
var heisenberg = {
name: 'Heisenberg',
sayMyName: function () {
console.log(`Your name is ${this.name}.`) // 'this' is heisenberg
}
}
sayMyName() // Your name is Beyonce.
heisenberg.sayMyName() // Your name is Heisenberg.
The code above works fine, but we repeated line 4 which is not cool (remember: DRY Don't Repeat Yourself).
There is a way to write the console.log()
only once and reuse it. To do that, we use the function bind
.
'this' with bind
Bind
applies a given 'this'
(an object) to the function that is calling it. The object that you want to bind to the function is passed as a parameter to bind.
See example:
function sayMyName(){
console.log(`Your name is ${this.name}.`)
}
var beyonce = {
name: 'Beyonce',
}
var heisenberg = {
name: 'Heisenberg',
}
let sayBeyonce= sayMyName.bind(beyonce)
let sayHeisenberg= sayMyName.bind(heisenberg)
sayBeyonce() // Your name is Beyonce.
sayHeisenberg() // Your name is Heisenberg.
Nice! Now, let's say we didn't want to create new functions to say each person's name. We only want to use sayMyName() .
We can do so with the call
function and a generic person object.
'this' with call
Like bind, call
can be used to set a custom value to 'this'
.
See the example:
var person = {
sayMyName: function(){ console.log(`Your name is ${this.name}.`)};
}
var beyonce = {
name: 'Beyonce',
};
var heisenberg = {
name: 'Heisenberg',
};
person.sayMyName.call(beyonce); // Your name is Beyonce.
person.sayMyName.call(heisenberg); // Your name is Heisenberg.
'this' with arrow functions
Be careful with arrow functions 🏹
When an arrow function is used, it doesn’t set a new value to 'this'
. Instead, it inherits the one from the parent scope.
This example is identical to the previous one, but with an arrow function instead of a normal one.
It logs "Ash" twice to the console. Weird, right?
var name = 'Ash';
var person = {
sayMyName: () => console.log(`Your name is ${this.name}.`)
};
var beyonce = {
name: 'Beyonce',
};
var heisenberg = {
name: 'Heisenberg',
};
person.sayMyName.call(beyonce); // Your name is Ash.
person.sayMyName.call(heisenberg); // Your name is Ash.
Even if you use call/bind, it won't work. It still logs "Ash". Why?
'this' with regular vs arrow functions
Regular functions set their own 'this'
object to the caller.
BUT, Arrow functions don't. They inherit 'this'
from the previous context, aka from the scope it sits inside. In this case, from window. This is called "lexical scoping".
So, when we used an arrow function, 'this'
had nothing to do with the caller of the function. It was still equal to window
and it stayed that way, logging "Ash" as a result.
What if we wrap the arrow function with a regular function?
The regular function is called and sets 'this'
to the caller person.
The arrow function is called from inside the regular function. 'this' value in the arrow function inherits 'this' value from the outer (regular) function. So it works!
var name = 'Ash';
var person = {
sayMyName: function () {
const arrowFunction = () => console.log(`Your name is ${this.name}.`);
arrowFunction();
},
};
var beyonce = {
name: 'Beyonce',
};
var heisenberg = {
name: 'Heisenberg',
};
person.sayMyName.call(beyonce); // Your name is Beyonce.
person.sayMyName.call(heisenberg); // Your name is Heisenberg.
Cool. So using arrow functions is bad? Not at all. There are many use cases when you actually want to inherit 'this' from the surrounding context. In those cases, arrow functions are super useful.
Useful cases of 'this' with arrow functions
Let's see an example. Here, we want to log a different name every 2 seconds by using an array of names. If we run this code, we get the error: [Uncaught TypeError: Cannot read property 'forEach' of undefined].
var people = {
names: ['Ash', 'Beyonce', 'Heisenberg'],
sayNames: function () {
// log each name after 1 second
setTimeout(function () {
console.log(this);
this.names.forEach(function (name) {
console.log('your name is' + name);
});
}, 2000);
},
};
people.sayNames();
Why?
When sayNames is called it sets 'this' to be the people object. But when setTimeout is called, it sets 'this' to be the window. The window doesn't have a names
property. How do we solve that?
You guessed it right! We use an arrow function, which will inherit the 'this' from its outer context. In other words, it will inherit 'this'
from sayNames context.
var people = {
names: ['Ash', 'Beyonce', 'Heisenberg'],
sayNames: function () {
console.log(this);
// log each name after 1 second
setTimeout( ()=> {
console.log(this);
this.names.forEach(function (name) {
console.log('your name is ' + name);
});
}, 2000);
},
};
people.sayNames();
About me, let's connect! 👋👩💻
Thanks for reading! I'm an avid learner and I love sharing what I know. I teach coding live for free 👉 here and I share coding tips on my Twitter . If you want to, come visit and say hi in the chat 😁
Top comments (2)
Nicely written! These days a 5 yo would probably learn the meaning of "this" in plain English from their understanding of it in js!
True :)