Understanding this, call, apply e bind in JavaScript

Complete Guide to this, call, apply, and bind

Published:

Understanding `this` in JavaScript

In JavaScript, the keyword this is a special identifier that refers to the context in which a function is executed. It determines the behavior of functions and which object they belong to. In short, this indicates the usage context. We will see various examples to understand how this points to the context and how it can be explicitly bound to a specific object or function call.

What is `this`?

this refers to the object from which the method or function in which it is used was invoked, but its value can vary depending on the call context.

Contexts of `this`

Value of this in Strict and Non-Strict Mode

In non-strict mode, this is always a reference to an object. In strict mode, however, it can be any value.

Here is an example showing how the value of this changes based on the mode:

// Non-strict mode
function nonStrictFunction() {
  console.log(this); // window (or the global object)
}
nonStrictFunction();

// Strict mode
'use strict';
function strictFunction() {
  console.log(this); // undefined
}
strictFunction();

Global Context

In the global context, this refers to the global object. In a browser, this object is window.

console.log(this); // window

Within a Function

In a function not in strict mode, this refers to the global object.

function globalFunction() {
  console.log(this); // window
}
globalFunction();

In strict mode, this is undefined.

'use strict';
function strictFunction() {
  console.log(this); // undefined
}
strictFunction();

Object Methods

When this is used within an object method, it refers to the object itself.

const person = {
  name: 'John',
  greet: function() {
    console.log(this.name); // John
  }
};
person.greet();

Constructors

When this is used within a constructor, it refers to the instance of the object created by the constructor function.

Using constructor function syntax:

function Person(name) {
  this.name = name;
}

const john = new Person('John');
console.log(john.name); // John

Using ES6 class syntax:

class Person {
  constructor(name) {
    this.name = name;
  }
}

const john = new Person('John');
console.log(john.name); // John

Arrow Functions

Arrow functions do not have their own this. Instead, they inherit this from the surrounding execution context at the time of their creation.

const person = {
  name: 'John',
  greet: () => {
    console.log(this.name); // undefined
  }
};
person.greet();

In the above case, this within the arrow function refers to the global context, not the person object.

Understanding the call, apply, and bind Methods in JavaScript

JavaScript offers three fundamental methods to manage the context (this) in functions: call(), apply(), and bind(). These methods allow you to modify the context in which a function is executed, which can be particularly useful for controlling function behavior.

call

The call method allows you to call a function with a specific value of this and a series of arguments passed individually.

Syntax

function.call(thisArg, arg1, arg2, ...)

Example

function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Mario' };

greet.call(person, 'Hello', '!'); // Output: Hello, Mario!

// Example 2
const car = {
  make: 'Toyota',
  model: 'Yaris',
  year: 2024
};

function describeCar(color, owner) {
  console.log(`${owner} owns a ${color} ${this.year} ${this.make} ${this.model}.`);
}

// Use call to describe the car
describeCar.call(car, 'blue', 'Alice');

apply

The apply method is similar to call, but instead of passing arguments individually, they are passed as an array or array-like object.

Syntax

function.apply(thisArg, [arg1, arg2, ...])

Example

function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Mario' };

greet.apply(person, ['Hello', '!']); // Output: Hello, Mario!

// Example 2
const car = {
  make: 'Toyota',
  model: 'Yaris',
  year: 2024
};

function describeCar(color, owner) {
  console.log(`${owner} owns a ${color} ${this.year} ${this.make} ${this.model}.`);
}

const args = ['red', 'Bob'];

// Use apply to describe the car
describeCar.apply(car, args);

bind

The bind method creates a new function that, when called, has its this value set to a specific value and, optionally, a series of preset arguments.

Syntax

const newFunction = function.bind(thisArg, arg1, arg2, ...)

Example

function greet(greeting, punctuation) {
  console.log(greeting + ', ' + this.name + punctuation);
}

const person = { name: 'Mario' };

const greetMario = greet.bind(person, 'Hello');

greetMario('!'); // Output: Hello, Mario!

// Example 2
const person = {
  firstName: 'John',
  lastName: 'Doe'
};

function logDetails(age, occupation) {
  console.log(`${this.firstName} ${this.lastName} is ${age} years old and works as a ${occupation}.`);
}

// Use bind to create a new function with this bound to person
const logJohnDetails = logDetails.bind(person, 30);

// You can now call the function with the last argument
logJohnDetails('developer'); // Output: John Doe is 30 years old and works as a developer.

When to use call, apply, and bind

  • Use call when you want to immediately execute a function with a specific value of this and a series of individually passed arguments.
  • Use apply when you want to immediately execute a function with a specific value of this and an array of arguments.
  • Use bind when you want to create a new function with a predefined this value and, optionally, preset arguments, to be called later.

Conclusion

Understanding call, apply, and bind is essential for mastering the behavior of this in JavaScript and writing more flexible and reusable code. By using these methods, you can precisely control the execution context of your functions, improving the readability and maintainability of your code.