The this
keyword in JavaScript has different values based on its context. Ignoring this important detail can lead to confusion and bugs in your code. In this article, we will explore the different behaviors of this
and how to use it effectively.
The this
Keyword in Strict Mode
In strict mode, the this
keyword outside of any object is always undefined
. However, in the default sloppy mode, this
refers to the global object (window
in a browser context), unless specific cases override this behavior.
The this
Keyword in Methods
A method in JavaScript is a function that is attached to an object. When using a regular function as a method, this
is automatically bound to the object it belongs to. Take a look at the example below:
const car = {
maker: 'Ford',
model: 'Fiesta',
drive() {
console.log(`Driving a ${this.maker} ${this.model} car!`);
}
}
car.drive();
// Output: Driving a Ford Fiesta car!
You can also achieve the same result by declaring the method using the function
keyword:
const car = {
maker: 'Ford',
model: 'Fiesta',
drive: function() {
console.log(`Driving a ${this.maker} ${this.model} car!`);
}
}
However, arrow functions behave differently. They are lexically bound, meaning that this
is derived from the context where they are defined. As a result, arrow functions do not have their own this
binding. Here’s an example:
const car = {
maker: 'Ford',
model: 'Fiesta',
drive: () => {
console.log(`Driving a ${this.maker} ${this.model} car!`);
}
}
car.drive();
// Output: Driving a undefined undefined car!
Binding Arrow Functions
Unlike regular functions, arrow functions cannot have their this
value bound to a specific object. The binding is not possible due to the way they work.
Explicitly Binding the this
Value
JavaScript provides several methods to bind the this
value to a specific object. Here are a few examples:
- Using the
bind()
method during function declaration:
const car = {
maker: 'Ford',
model: 'Fiesta'
}
const drive = function() {
console.log(`Driving a ${this.maker} ${this.model} car!`);
}.bind(car);
drive();
// Output: Driving a Ford Fiesta car!
- Binding an existing object method to a different object:
const car = {
maker: 'Ford',
model: 'Fiesta',
drive() {
console.log(`Driving a ${this.maker} ${this.model} car!`);
}
}
const anotherCar = {
maker: 'Audi',
model: 'A4'
}
car.drive.bind(anotherCar)();
// Output: Driving a Audi A4 car!
- Using the
call()
orapply()
method during function invocation:
const car = {
maker: 'Ford',
model: 'Fiesta'
}
const drive = function(kmh) {
console.log(`Driving a ${this.maker} ${this.model} car at ${kmh} km/h!`);
}
drive.call(car, 100);
// Output: Driving a Ford Fiesta car at 100 km/h!
drive.apply(car, [100]);
// Output: Driving a Ford Fiesta car at 100 km/h!
The first parameter passed to call()
or apply()
binds this
to the specified object. The difference between call()
and apply()
lies in how the arguments are passed. call()
accepts a variable number of parameters, while apply()
requires an array of arguments.
The Special Case of Browser Event Handlers
In event handler callbacks, this
refers to the HTML element that received the event. To bind this
to a specific context, you can use the bind()
method. Here’s an example:
document.querySelector('#button').addEventListener(
'click',
function(e) {
console.log(this); // Refers to the HTML element
}.bind(this)
);
Understanding the behavior of the this
keyword in JavaScript is crucial for writing clean and bug-free code. It’s worth taking the time to familiarize yourself with the different use cases and tricks to leverage this
effectively.