const - JS | lectureA Closer Look At Functions

The Bind Method

A Closer Look At Functions

Like the call method, bind allows us to manually set the this keyword for any function call. Now, the difference is that bind does not immediately call the function. Instead, it returns a new function where the this keyword is bound. That is, it's set to whatever value we pass into bind.

Let's consider the airline example from the previous lecture. And now, let's say we need to use the book function for the Emirates Executive airline all the time. In case you don't remember, this is what we had in the previous lecture:

const emirates = {
  airline: 'Emirates',
  iata: 'EK',
  bookings: [],
  book(flightNumber, passengerName) {
    console.log(
      `${passengerName} booked flight ${this.iata}${flightNumber} on ${this.airline}`
    );
    this.bookings.push({
      flight: `${this.iata}${flightNumber}`,
      passengerName,
    });
  },
};

const emiratesExecutive = {
  airline: 'Emirates Executive',
  iata: 'EE',
  bookings: [],
};

const book = emirates.book;

book.call(emiratesExecutive, 789, 'Mike Smith');

As you can see from the above code, we used book.call to use the book function with emiratesExecutive set as the this keyword. That's what we had in the previous lecture. But as mentionned above, we use the bind method to create a new function that has emiratesExecutive set as the this keyword.

So, keep in mind that doing:

book.bind(emiratesExecutive);

Will not call the function. It will return a new function where the this keyword will always be set to emiratesExecutive.

const bookBoundToEmiratesExecutive = book.bind(emiratesExecutive);

Let's now use this function to book a flight.

bookBoundToEmiratesExecutive(905, 'Willie Santos');

As you can see, the bookBoundToEmiratesExecutive function now looks like the normal book function call. That's because it already has the this keyword set in stone. Reason why when calling it, we no longer need to specify the this keyword again. Hence the signature. i.e., the name of the parameters is back to being simply the flight number and passenger name.

Let's check the output...

Bind output

From the above output, we can see that it works as expected. We can now move on and do the same for all the airlines. Creating one booking function for each airline. This then makes booking a flight for each airline a little bit easier if we have to do it multiple times. So instead of having to use call all the time, we can just do bind once, and from there on, we can use the same function.

const bookBoundToEmiratesExecutive = book.bind(emiratesExecutive);
const bookBoundToEmirates = book.bind(emirates);
const bookBoundToEmiratesSkyCargo = book.bind(emiratesSkyCargo); // From previous lecture!

Now that you understand how the bind method works, let's take this a little bit further. As we've seen in the previous lecture, we can pass multiple arguments besides the this keyword when using the call method. We can do the same thing with the bind method. When passing the arguments to the bind method, they will be set in stone. They will be defined, and the function will always be called with these same arguments.

For example, let's say we want to create a function for a specific airline and a specific flight number.

const bookBoundToEmiratesExecutive579 = book.bind(emiratesExecutive, 579);

Doing this will set the flight number to 579. And all we are left with is to provide the passenger name.

bookBoundToEmiratesExecutive579('David Logan');
bookBoundToEmiratesExecutive579('Rosetta Barton');

Bind - pass arguments

Specify part of the arguments before hand is actually a common pattern called partial application. Partial application essentially means that a part of the arguments of the original function are already applied. i.e., they are already set. And that exactly what the bookBoundToEmiratesExecutive579function is. Its essentially the book function but with 579 already predefined.

Hopefully this was a nice example for you to understand the call, apply and bind methods. But there are other situations in which we can use the bind method, and where it is very useful. For example, when we want to use objects together with event listeners.

Let start by adding a property and a method to the emirates object.

emirates.numberOfPlanes = 300;

emirates.buyPlane = function () {
  console.log(this);
  this.numberOfPlanes++;
  console.log(this.numberOfPlanes);
};

Next, if you haven't yet, create an HTML file and link your script file to it. Then, add the following code to the body of the HTML file:

<button id="buy">Buy a Plane</button>

Let's now attach our event handler to the buy button.

document.querySelector('#buy').addEventListener('click', emirates.buyPlane);

Now when you click on the button, you will notice that you have the below output in the console:

Bind & Event Listeners

The value of this.numberOfPlanes is NaN (Not a Number). And the reason why we are have that is because the this keyword is the button element. Do you remember why? Well, in one of the previous lectures, we learned that in an event handler function, the this keyword always points to the element on which that handler is attached to. Reason why the value of this in the console returned the button element.

This is yet another proof that the this keyword is set dynamically. Because if we try to call the buyPlane method directly, .i.e., not as a callback function, the this keyword will be set to the emirates object.

emirates.buyPlane();

Bind & Event Listeners - 1

To fix the issue with our event handler, we need the this keyword to point to the emirates object and not the button element. Otherwise the logic in the buyPlane method will not work. So what this means is that we need to manually define the this keyword. Now the question is, Now, how should we do that? Should we use the call or the bind method? Well, in the addEventListener method, we only need to pass in a function and not call it. And from what we have learned up until now, the call method isn't the best option because it will immediately call the function. Therefore, we will use the bind method.

We will use the bind method because we already know that it doesnt call the function immediately but returns a new function. All that's now left for us to do is to set the this keyword to the emirates object.

document
  .querySelector('#buy')
  .addEventListener('click', emirates.buyPlane.bind(emirates));

Now, if we click again on the button, the this keyword should point to the emirates object. With the number of planes increasing every time we click on the button.

You really need too understand this lecture because we will do it a couple more times throughout the course. And in general, the bind method is something you really need to understand.

Let's have one final example here, which is, again, going to be about partial application, because this is another big use case for the bind method. And in this case of partial application, we are often not even interested in the this keyword, but we still use bind for this.

Remember that partial application means that we can preset parameters. So let's start by creating a general function that adds a tax to some value.

const addTax = function (value, taxRate) {
  return value + value * taxRate;
};

addTax(100, 0.1); // 110

What we just wrote above is the general function for adding tax. But now, let's say there is one tax we use all the time. Hence, let's create a function for that.

const addVAT = addTax.bind(null, 0.27);

As you can see we've used the bind method on the addTax function. The first agument of the bind method is the this keyword. But in this case we don't care about the this keyword. And it's not even in the addTax function. So we can just pass null (It can be any other value but null is kind of a standard) as the first argument. Now all we need to do is to preset the value of the tax rate. Which we did by passing 0.27 as the second argument. Now each time we call the addVAT function, the tax rate will always be 0.27.

Alright! So I hope this makes sense. When you want to do it yourself, just keep in mind that the order of arguments matters. Now you could argue that what we just did above could easily be have been done with default parameters. But it's actually different because bind creates a brand new more specific function based on a more general function, which is the addTax function.