- These functions are usually used when we want to set the
this
keyword independent of how the function is being called in our code.
Lets understand this in a clear way with an example. Assume a flight company minimal object, it stores the
name of the flight
- the
iata code
(location identifier code) - the
bookings
array and - has a method
book
that books the flight using the flight name and the name of the passenger as the arguments.
const airIndia = {
airline: 'Air India',
iataCode: 'AI3',
bookings: [],
book(flightNum, name) {
console.log(`${name} booked a seat on ${this.airline} flight ${this.iataCode}${flightNum}`);
this.bookings.push({ flight: `${this.iataCode}${flightNum}`, name });
}
}
Now, to book a flight we can simply call the book method and pass in the passenger name and the flightNumber.
airIndia.book(111, 'RahulK');
airIndia.book(112, 'devtuber');
// Output:
// RahulK booked a seat on Air India flight AI3111
// devtuber booked a seat on Air India flight AI3112
Up until here, there was nothing to do with the call, apply and bind functions. But, now lets take it to the next step. Lets assume that AirIndia opens up a new subsidiary airline 'flyer'.
The object should have similar properties as to airIndia.
const flyer = {
airline: 'Flyer',
iataCode: 'FF3',
bookings: [],
book(flightNum, name) {
console.log(`${name} booked a seat on ${this.airline} flight ${this.iataCode}${flightNum}`);
this.bookings.push({ flight: `${this.iataCode}${flightNum}`, name });
}
}
// It will use the book method from the parent airline(AirIndia).
So, here we would exploit the DRY principle if we re-wrote the book() method within the flyer object. How can we improve this?
What happens when we try to use the book() from AirIndia object?
const bookTicket = airIndia.book;
bookTicket(24, 'Rahul'); // error
this will certainly give an error because when we store the book() method into the bookTicket, bookTicket no longer remains the method rather becomes the normal function whose this keyword points to undefined.
Things to remember:
this
always refers to an object.this
refers to an object which calls the function it contains.- In the
global
contextthis
refers either to thewindow
object or isundefined
if the strict mode is on.
How to solve this?
- One way is to create a book function explicitly that takes in three arguments:
airline object
,passenger name
,flight number
and books the flight for any airline. - Second way is to set the value of
this
using either the call(), apply() or bind() methods while calling book() from AirIndia.
Using Call(thisArg, ...parameters)
The call() method sets the 'this' inside the function and immediately executes that function.
- Syntax: function.call(thisArg, param1, param2...)
So, now instead of passing only the parameters asked in the bookTicket(), we can also pass the object to which the this
should reference to using the call().
const bookTicket = airIndia.book;
bookTicket.call(flyer, 24, 'Rahul');
// Output: Rahul booked a seat on Flyer flight FF224
Using Apply(thisArg, [param1, param2...])
Apply() method works similar to call(), it also sets the 'this' inside the function and immediately executes that function.
Only difference is that it takes the arguments in the form of an array.
const bookTicket = airIndia.book;
bookTicket.apply(flyer, [24, 'Keyboard']);
// Output: Keyboard booked a seat on Flyer flight FF224
Using Bind(thisArg, optionalArguments)
Bind() actually works similar to call() and apply() but has some differences. The main difference is that bind() method creates a new function that, when called, has its this keyword set to the provided value.
const bookBind = airIndia.book.bind(flyer);
bookBind(24, 'Rahul');
// Output: Rahul booked a seat on Flyer flight FF224
Optionally, we can always provide the other arguments as well within the bind() method. We are allowed to pass in partial arguments too. Let make it clear through an example.
const bookBind = airIndia.book.bind(flyer, 25);
bookBind('Rahul');
// Output: Rahul booked a seat on Flyer flight FF225
In the above code, we have optionally passed the flight number and not the name within the bind() method, which is perfectly fine.
const bookBind = airIndia.book.bind(flyer, 25, 'Rahul');
bookBind();
// Output: Rahul booked a seat on Flyer flight FF225
In the above code, we have passed both the flight number and the name within the bind() method, which is perfectly fine too.