Using "this" keyword with call(), apply(), and bind()

Article explaining what the "this" keyword is and how to explicitly bind it with three different methods

Published Aug. 17, 2022

What is "this"?

In a nutshell, this is a keyword in JavaScript that holds a reference to the object that you're currently working with. It's a lot easier to understand with a visual example:


class Human {
  constructor(gender, age) {
    this.gender = gender;
    this.age = age;
  }
}

const man = new Human("male", 23);
const woman = new Human("female", 26);

console.log(man.gender); // male
console.log(woman.gender); // female
        

...here, a Human class with two properties is initialized. We then create two instances of that class: man and woman. In the context of man, this refers to that object, so it becomes man.gender and man.age. In the context of woman, this refers to woman.gender and woman.age.

this simply refers to the object that's currently using the constructor. This is all done implicitly, but what if we want to explicity control what this refers to?

call(), apply(), and bind()

By default, the this keyword is implicitly defined by its context, giving you no control over what it refers to, although it can be controlled by explicitly defining it with one of three methods — call(), apply(), or bind(). Let's start with the call() method:


const movie = {
  title: "The Dark Knight",
  releaseDate: 2008,
};

function showMovieDetails() {
  console.log(`${this.title} was released in ${this.releaseDate}.`);
}

showMovieDetails();
// undefined was released in undefined.
        

...when showMovieDetails is invoked, the console logs the title and releaseDate as undefined, which makes sense because the showMovieDetails function has nothing to do with the movie object, so this holds no context. Luckily, we can use the call() method to assign the the properties of movie to this...


showMovieDetails.call(movie);
// The Dark Knight was released in 2008.
        

...the call() method takes in the name of the object that you want to assign the this keyword to. Pretty simple, right? The apply() method is super similar...


showMovieDetails.apply(movie);
// The Dark Knight was released in 2008.
        

...what's the difference? Well, let's add a bit more to our example...


const movie = {
  title: "The Dark Knight",
  releaseDate: 2008,
};

function showMovieDetails(firstName, lastName) {
  console.log(
    `${this.title} was released in ${this.releaseDate}, and was directed by ${firstName} ${lastName}.`
  );
}

showMovieDetails.call(movie, "Christopher", "Nolan");
// The Dark Knight was released in 2008, and was directed by Christopher Nolan.

showMovieDetails.apply(movie, "Christopher", "Nolan");
// UncaughtTypeError: CreateListFromArrayLike called on non-object
        

...the showMovieDetails function has two parameters now: firstName and lastName. Both call() and apply() can receive additional arguments, but how come the apply() method throws an error? Well, the only difference between both methods is that apply() takes in arguments as an array, whereas call() receives them individually...


showMovieDetails.call(movie, "Christopher", "Nolan");
// The Dark Knight was released in 2008, and was directed by Christopher Nolan.

showMovieDetails.apply(movie, ["Christopher", "Nolan"]);
// The Dark Knight was released in 2008, and was directed by Christopher Nolan.
        

...whereas call() and apply() immediately invoke the specified function with the given value, the bind() method works a little differently. Instead, it returns a new function that when invoked, uses the given value...


const batmanFacts = showMovieDetails.bind(movie, "Christopher", "Nolan");
batmanFacts();
// The Dark Knight was released in 2008, and was directed by Christopher Nolan.
        

...this gives us the liberty to invoke the batmanFacts() function anywhere in our program while preserving the context of this, which in this case is the movie object.

To summarize, call(), apply(), and bind() are all used to control what the this keyword refers to. call() takes in arguments individually, whereas apply() takes them in as an array. Both of these methods immediately invoke the function, unlike bind(), which returns a new function that can be executed later.