DEV Community

Cover image for Understanding call, apply and bind methods in Javascript
Jahid Hasan
Jahid Hasan

Posted on

Understanding call, apply and bind methods in Javascript

Three little methods. One big idea: you control what this points to.


Every time you write a function in JavaScript, there's a hidden element — the this keyword. Usually, it works fine, but when you extract a method or pass it as an event listener, this can point somewhere unexpected, causing confusing bugs.

call, apply, and bind are the tools that help manage that hidden element. Let's explore with an example involving a bus company 🚌.


The Example Setup

Consider Purbasha Paribahan, a local bus company modeled as an object with a book method to record passenger reservations.

const purbasha = {
  busName: 'Purbasha Paribahan',
  busCode: 'PB',
  bookings: [],
  book: function(busNum, passengerName) {
    console.log(
      `${passengerName} has booked a seat on ${this.busName} with bus ${this.busCode}${busNum}.`
    );
    this.bookings.push({ bus: `${this.busCode}${busNum}`, passengerName });
  }
};
Enter fullscreen mode Exit fullscreen mode

Calling the function normally works perfectly:

purbasha.book(12, 'Sumon');
Enter fullscreen mode Exit fullscreen mode

Output: Sumon has booked a seat on Purbasha Paribahan with bus PB12.

Inside book, this refers to purbasha — exactly as intended. But things get interesting when a rival enters the scene.

A competing company, Royal Express, needs similar booking functionality. Repeating the method isn't ideal, so we introduce our three heroes.

const royal = {
  busName: 'Royal Express',
  busCode: 'RE',
  bookings: []
};
Enter fullscreen mode Exit fullscreen mode

Method 1: call — Invoke Immediately with Arguments as a List

First, get the book function separately, then use .call() to invoke it with this set to the desired object, passing arguments individually.

const book = purbasha.book; // separate function reference

book.call(royal, 45, 'Tanvir');
Enter fullscreen mode Exit fullscreen mode

Output: Tanvir has booked a seat on Royal Express with bus RE45.

What's happening?
call runs book immediately, manually setting this to royal. It's like: "Use this function but treat it as if it belongs to royal".

Argument Description
1st Object to assign this
2nd, 3rd, ... Function arguments

Method 2: apply — Same as call, Arguments in an Array

apply is similar but takes arguments as an array, useful when data is already in an array.

const passengerData = [23, 'Mahfuz'];

book.apply(purbasha, passengerData);
Enter fullscreen mode Exit fullscreen mode

Output: Mahfuz has booked a seat on Purbasha Paribahan with bus PB23.

Tip: With ES6+, you can use the spread operator with call instead:
book.call(purbasha, ...passengerData);

Method Argument Passing
call Individually listed
apply In an array

Method 3: bind — Create a New Function with this Set

bind doesn't run the function immediately. Instead, it returns a new function with this permanently set, which you can call later.

const bookRE = book.bind(royal); // new function

bookRE(56, 'Mustak'); // call the new function
Enter fullscreen mode Exit fullscreen mode

Output: Mustak has booked a seat on Royal Express with bus RE56.


Using bind for Partial Application

bind is especially useful for partial application, where you preset some arguments.

// preset `this` and bus number 56
const bookRE56 = book.bind(royal, 56);

bookRE56('Robin');
bookRE56('Rafi');
Enter fullscreen mode Exit fullscreen mode

Output:

Robin has booked a seat on Royal Express with bus RE56.
Rafi has booked a seat on Royal Express with bus RE56.
Enter fullscreen mode Exit fullscreen mode

Note: Partial application is creating specialized functions by presetting some arguments.


Common Pitfall: Event Callbacks

Using object methods as event handlers often causes this to break. Here's an example:

purbasha.buses = 100;
purbasha.buyBus = function() {
  this.buses++;
  console.log(this.buses);
};

// ❌ Wrong — don't do this
document.querySelector('.buy')
  .addEventListener('click', purbasha.buyBus);
Enter fullscreen mode Exit fullscreen mode

Click, and you'll see NaN, not 101. That's because in event callbacks, this refers to the DOM element (the button), which lacks a buses property, leading to undefined++, resulting in NaN.

Rule of thumb: When passing methods as callbacks, this can lose its original context.

To fix, bind the method:

// ✅ Correct — bind `purbasha` as 'this'
document.querySelector('.buy')
  .addEventListener('click', purbasha.buyBus.bind(purbasha));
Enter fullscreen mode Exit fullscreen mode

Now, this inside buyBus always refers to purbasha, no matter the event source.


Quick Reference

Method Executes? Argument Passing Use Case
call Yes, immediately Individual args One-off with specific this
apply Yes, immediately Arguments in array When data is in an array
bind No — returns a new func Pre-set args optional Callbacks, partials

That's it! Understanding these methods as different ways to specify "this" makes them less mysterious and more natural to use.

Questions? Comments? Feel free to ask!

*Inspired by Jonas Schmedtmann's JavaScript course on Udemy.

Top comments (0)