Understanding `this`
In simple terms, the this
keyword refers to the object.
You are always “binding” some object to where this
is called. What object you are binding depends on the context.
Global Context
In the global context, this
refers to the global object, which is often window
in web browsers and global
in NodeJS (but both depend on strict mode, configuration,…).
What this means is basically whenever you call this
in the global context you are “binding” a global object to be this
.
console.log(this === global); // In NodeJS, this should be true*
console.log(this === window); // In JS in browser, this should be true*
// * - depends on configurations...
Function Context
Here we have two different examples, where this
refers to different objects. This is because the function itself is executed in different contexts.
Generally, this
is an object that called the function.
function test() {
console.log(this);
}
test(); // window object in browser JS
Above, we are taking our default object window
and “binding” it to this
. This happens automatically.
const person = {
name: "Mario",
greet: function () {
console.log(`Hello ${this.name}`);
},
};
person.greet(); // Output: "Hello Mario"
But here, we have another object person
that is automatically being bound to be this
and then it makes sense that this.name
is Mario
.
function hello() {
console.log(`Hello ${this.name}`);
}
const person = {
name: "Mario",
sayHello: hello,
};
hello(); // Output: Hello undefined
person.sayHello(); // Output: Hello Mario
Another example that shows that if we execute hello
directly then this
does not contain name
property (even if it is window
object in case of browser) and we get undefined
. However, if called in context of person
object then that object gets bound to this
.
Arrow Functions
Arrow functions behave differently with the this
keyword even if in some cases it appears its not. This is related to something called lexical scope
(⏭️). Whereas before we have an object that called
the function bound to this
, with arrow functions this
is always the object that defined
the arrow function.
function first() {
console.log(this);
}
const second = () => {
console.log(this);
};
first(); // window/global/undefined
second(); //window/global/undefined
Above, the results are the same for both. But lets look at next examples:
const person = {
name: "Mario",
greet: () => {
console.log(`Hello, my name is ${this.name}`);
},
};
person.greet(); // Output: "Hello, my name is undefined"
const person = {
name: "Mario",
greet: function () {
const inner = () => {
console.log(`Hello, my name is ${this.name}`);
};
inner();
},
};
person.greet(); // Output: "Hello, my name is Mario"
Some parts below are copied from freeCodeCamp as it is very nicely explained.
When inside an object, the this
keyword refers to the current object only when you declare the method using the standard syntax (methodName()
or methodName: function(){ }
) .When you declare an object method using the arrow function
, the this
keyword refers to the global object.
Never use the arrow function when declaring a method. However, you can do something like this:
const person = {
name: "Nathan",
skills: ["HTML", "CSS", "JavaScript"],
showSkills() {
this.skills.forEach(function (skill) {
console.log(`${this.name} is skilled in ${skill}`);
});
},
};
person.showSkills();
// Outputs:
// undefined is skilled in HTML
// undefined is skilled in CSS
// undefined is skilled in JavaScript
Here, the this
keyword refers to the window
object because we called the showSkills()
method outside of the person
object.
In the global
object, the name
property is undefined.
const person = {
name: "Nathan",
skills: ["HTML", "CSS", "JavaScript"],
showSkills() {
this.skills.forEach((skill) => {
console.log(`${this.name} is skilled in ${skill}`);
});
},
};
person.showSkills();
// Outputs:
// Nathan is skilled in HTML
// Nathan is skilled in CSS
// Nathan is skilled in JavaScript
Here, the this
keyword refers to the object from which the arrow function is defined
, which is the person
object.
This one behavior is what makes people prefer arrow functions, because it makes more sense to have this refer to the object from which you define
that function rather than from which you call
it.
What now?
Now you have the ability to expand your existing code and use this
. Try to use above examples as a insipiration on what to try out next.