If you program in JavaScript regularly, you've probably come across the mysterious this
keyword.
At first, it may seem very complicated and confusing.
But don't worry! 😉 In this article, I'll explain exactly what this
is in JavaScript, how it works in different contexts, and why it's important to understand what it refers to in various situations.
I'll show you how this
functions in the global context, in object methods, arrow functions, constructor functions, and also when using methods like bind()
, call()
, and apply()
.
Let's get started 🚀
Introduction to this in JavaScript 🧑💻
This
in JavaScript refers to the context in which a function is called, and its value can vary depending on how the function is defined and used.
This means that in one case, this
may refer to the global object, while in another case, it may refer to a specific object or an instance created by a constructor function.
At first, this might sound complex, but in reality, there are some clear rules that allow you to understand how this
works in different contexts.
Here are the main use cases for this
:
- Global context –
this
refers to the global object, which iswindow
in browsers orglobal
in Node.js. - Object methods –
this
refers to the object that calls the method. - Arrow functions –
this
inherits its context from where the function was defined, not where it was called. - Constructor functions –
this
refers to the newly created object instance. - Methods like
bind()
,call()
, andapply()
– these methods allow you to manually manipulate the value ofthis
, setting it to any object.
Understanding how this
works is essential if you want to master JavaScript and build efficient and flexible applications.
This in the Global Context 🌐
In the global context, this
refers to the global object. In browsers, this is the window
object, meaning that when a function is called in the global context, this
defaults to pointing to the window
object.
function showThis() {
console.log(this); // window object in the browser
}
showThis();
As you can see above, calling the showThis()
function in a browser results in this
referring to the window
object. In a Node.js environment, the value of this
in the global context points to the global
object.
However, when working in strict mode, the value of this
in the global context changes and returns undefined
. Let's see how that works.
Strict Mode 🚨
When you enable strict mode in JavaScript (by adding "use strict";
at the beginning of a file or function), JavaScript becomes more restrictive in certain situations, which can help avoid errors that might go unnoticed in normal mode.
One of the side effects of enabling strict mode is the change in behavior of this
in the global context.
"use strict";
function showThisStrict() {
console.log(this); // undefined
}
showThisStrict();
As you can see, after enabling strict mode, this
in the global context returns undefined
instead of referring to the window
object.
This helps prevent accidental references to global objects, which is a common source of errors in larger applications.
This in Object Methods 🛠️
When a function is called as a method of an object, the value of this
refers to that specific object. Let's take a look at the following example:
const person = {
name: "Alice",
introduce() {
console.log(`Hi! My name is ${this.name}`); // Hi! My name is Alice
},
};
person.introduce();
In this case, this
refers to the person
object because it is the one calling the introduce()
method.
This means that you can access the properties of the object inside its methods using the this
keyword.
However, it's important to be aware of one common source of confusion with this
– situations where an inner function is defined inside an object's method.
This in Object Methods and Inner Functions 🤯
When you define an inner function within an object's method, the value of this
inside that function may change. Let's see this in practice:
const person = {
name: "Alice",
introduce() {
function innerFunction() {
console.log(this.name); // undefined
}
innerFunction();
},
};
person.introduce();
Why does this return undefined
? This happens because this
inside the innerFunction()
refers to the global object (window
in browsers) rather than the person
object.
To avoid such issues, arrow functions are often used, as they handle this
differently.
Arrow Functions 🏹
Arrow functions in JavaScript introduce a key difference in the behavior of this
.
In traditional functions, the value of this
depends on how the function was called.
However, arrow functions have lexical this
, meaning they inherit the value of this
from the place where they were defined.
Let's see an example:
const person = {
name: "Alice",
introduce() {
const innerFunction = () => {
console.log(this.name); // Alice
};
innerFunction();
},
};
person.introduce();
In this case, because innerFunction
is an arrow function, this
inherits its value from the surrounding context, which is the introduce()
method. Therefore, this
refers to the person
object.
Thanks to arrow functions, we can avoid issues with this
inside inner functions.
This is one of the main reasons arrow functions have become so popular in modern JavaScript.
This in Constructor Functions 🏗️
Constructor functions in JavaScript are special functions used to create new object instances.
When a function is called as a constructor (using the new
keyword), this
refers to the newly created object instance.
Let's take a look at an example:
function Person(name, age) {
this.name = name;
this.age = age;
}
const john = new Person("John", 28);
console.log(john.name); // John
console.log(john.age); // 28
In this case, when we call the Person
function using new
, we create a new object instance, and this
refers to that instance (john
).
The constructor allows us to assign properties to the newly created objects.
Manipulating this with bind(), call(), and apply() 🔄
Sometimes, we need to manually modify the value of this
for a given function.
In such cases, we can use the methods bind()
, call()
, and apply()
. Here's how each of them works in practice:
call()
– invokes a function withthis
set to any object you pass as the first parameter.
function greet() {
console.log(`Hello, my name is ${this.name}`);
}
const person = { name: "Tom" };
greet.call(person); // Hello, my name is Tom
apply()
– works similarly tocall()
, but instead of passing arguments directly, you need to provide them in an array.
function introduce(age, city) {
console.log(`${this.name} is ${age} years old and lives in ${city}`);
}
const person = { name: "Lucy" };
introduce.apply(person, [25, "New York"]); // Lucy is 25 years old and lives in New York
bind()
– creates a new function wherethis
is permanently set to the chosen object.
function sayHello() {
console.log(`Hello, ${this.name}`);
}
const person = { name: "Kate" };
const boundSayHello = sayHello.bind(person);
boundSayHello(); // Hello, Kate
Unlike call()
and apply()
, the bind()
method does not invoke the function immediately. Instead, it returns a new function with the bound this
value, which you can call later.
This and ES6 Classes 👷♀️
Since the introduction of classes in ES6, working with constructor functions has become more intuitive. Classes offer a clearer and more concise syntax for creating objects and working with this
.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise`);
}
}
const dog = new Animal("Dog");
dog.speak(); // Dog makes a noise
As we can see, in the case of ES6 classes, this
in methods refers to the object instance created by the constructor (dog
in this example).
Conclusion 🎯
This
in JavaScript is a crucial concept that allows you to manage the context of function calls dynamically.
Depending on where and how a function is called, this
can refer to the global object, a specific object, or a newly created instance.
Understanding how this
works is essential for any developer who wants to write efficient and flexible JavaScript code.
Arrow functions simplify working with this
, eliminating the problem of changing context, while methods like bind()
, call()
, and apply()
give you full control over assigning this
.
The introduction of ES6 classes further simplifies working with this
in constructors, making the code more readable and concise.
I hope this article helped you understand the workings of this
in JavaScript and makes it easier for you to continue mastering your craft.