Understanding JavaScript Binding: A Beginner's Guide to call(), bind(), apply(), and Lexical this

Understanding JavaScript Binding: A Beginner's Guide to call(), bind(), apply(), and Lexical this
Photo by Wynand Uys / Unsplash

In JavaScript, how functions are invoked and how their context (this keyword) is handled can sometimes feel confusing, especially for beginners. But understanding how JavaScript binding works is a fundamental skill that can unlock more effective and powerful code. In this article, we’ll demystify the call(), bind(), and apply() methods, and explain the concept of lexical this in JavaScript.


What Is this in JavaScript?

In JavaScript, this refers to the object that is currently executing the function. Its value is determined by how a function is called, not how it is defined. This is why this can be tricky to work with in certain contexts, like when passing functions as callbacks or working with event handlers.

However, JavaScript provides ways to control and bind the value of this explicitly using the call(), bind(), and apply() methods.


The call() Method

The call() method allows you to explicitly specify what this should refer to when calling a function.

Syntax

functionName.call(context, arg1, arg2, ...);

Example

const person = {
  name: "Alice",
  greet: function(greeting) {
    console.log(greeting + ", I am " + this.name);
  }
};

const otherPerson = {
  name: "Bob"
};

// Using call() to invoke the greet function with `this` set to `otherPerson`
person.greet.call(otherPerson, "Hello");
// Output: "Hello, I am Bob"

In the above example, even though the greet function is defined in the person object, by using call(), we set this to otherPerson, making it print "I am Bob" instead of "I am Alice".


The apply() Method

The apply() method is similar to call(), but instead of passing arguments one by one, you pass them as an array. It’s useful when you want to call a function with an array of arguments.

Syntax

functionName.apply(context, [arg1, arg2, ...]);

Example

const numbers = [5, 10, 15];
const sum = Math.max.apply(null, numbers);
console.log(sum); // Output: 15

In this example, apply() is used to pass the array of numbers to Math.max(), which returns the maximum value. The first argument (null) means we don't care about the value of this for Math.max(), since it doesn't use it.


The bind() Method

Unlike call() and apply(), the bind() method doesn’t immediately invoke the function. Instead, it creates a new function with a permanent this binding, which can be used later.

Syntax

const boundFunction = functionName.bind(context, arg1, arg2, ...);

Example

const car = {
  brand: "Toyota",
  showBrand: function() {
    console.log(this.brand);
  }
};

const displayCarBrand = car.showBrand.bind(car);
displayCarBrand(); // Output: "Toyota"

In this example, the bind() method permanently binds the value of this to car, so when displayCarBrand() is called, it correctly refers to car.brand.

This method is particularly useful when passing functions around as callbacks, ensuring they maintain the right this context even when invoked elsewhere.


Lexical this: Arrow Functions

Arrow functions in JavaScript have a special behavior regarding this: they don’t have their own this context. Instead, they inherit this from the surrounding (lexical) context where they are defined. This can be very useful in situations where traditional functions might lose their this binding.

Example

const person = {
  name: "Charlie",
  sayName: function() {
    setTimeout(() => {
      console.log(this.name);
    }, 1000);
  }
};

person.sayName(); // Output after 1 second: "Charlie"

In this example, the arrow function inside setTimeout() inherits this from the sayName method’s context (which is person). Without arrow functions, using a regular function for setTimeout() would result in this being undefined, or referring to the global object.


When to Use call(), apply(), and bind()

  • Use call() when you want to invoke a function immediately and change the context of this.
  • Use apply() when you want to invoke a function immediately with an array of arguments and change the context of this.
  • Use bind() when you want to create a new function with a permanently bound this that you can invoke later.
  • Use arrow functions when you want to maintain the this value from the surrounding lexical scope.

Finally

Understanding how JavaScript binding works and knowing when to use call(), apply(), bind(), and lexical this will help you write cleaner, more flexible code. While these concepts can be tricky at first, practice will make them second nature, allowing you to master function contexts and improve your JavaScript skills.

Support Us

Subscribe to Buka Corner

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe