Function Borrowing Methods in JavaScript

call(), bind() & apply()

Function Borrowing Methods in JavaScript

❓ What is Function Borrowing?

In JavaScript, the concept of function borrowing allows us to reuse the methods of one object on another object. In other words, we can borrow the methods of one object and use them on another object.

This prevents making the copy of the same method at two (or more) different places.

Before getting into Function Borrowing, we first need to understand two more concepts: Implicit Binding & Explicit Binding

🆚 Implicit vs Explicit Binding

Implicit, as the name suggests, means in-built. Whenever we invoke a method of an object using the dot notation, the this keyword will point to the object with which it was invoked. This is known as Implicit Binding.

For example,

1. const person = {
2.   firstName: "John",
3.   lastName: "Doe",
4.   sayHi: function () {
5.     console.log(`Hello, ${this.firstName} ${this.lastName}`);
6.   }
7. };

8. person.sayHi(); // Hello, John Doe

Here, line 8 invokes the method sayHi() of the object person. This represents implicit binding.

Explicit binding comes into the picture when we want to access the methods of an object with the values provided by another object. To achieve explicit binding, we need to use one of the Function Borrowing methods.

Predominantly, JavaScript provides 3 different methods to borrow functions (or methods):

  1. bind()
  2. call()
  3. apply()

All of these methods are different from one another and have their own use-case.

Let us understand each one of them using examples:

🤝 bind()

The bind() method creates and returns a new function, whose this keyword is set to the object which was passed to it.

It binds a method to an object and returns a function to be invoked later.

Let's see an example:

1. const person = {
2.   firstName: "John",
3.   lastName: "Doe",
4.   sayHi: function () {
5.     console.log(`Hello, ${this.firstName} ${this.lastName}`);
6.   }
7. };

8. person.sayHi(); // Hello, John Doe

9. const person2 = {
10.   firstName: "Bob",
11.   lastName: "Builder"
12. };

13. const greet = person.sayHi.bind(person2);
14. greet(); // Hello, Bob Builder

Here, on line 1, we have an object person which has a method sayHi(). So, line 8 prints Hello, John Doe to the console. This is the normal scenario where the this keyword of the method is bound to the object person, due to which the properties firstName and lastName point to those of the person object. This concept is referred to as Implicit Binding.

We also have another object person2 on line 9. On line 13, we are binding the sayHi() method to object person2. This means that the this keyword will now refer to person2, so the properties firstName and lastName will now be taken from the person2 object. Also, the bind() method does not invoke the sayHi() function by itself. It instead returns a function that can be invoked later.

On line 14, when we invoke the greet() function, the output is printed on the console. And as discussed above, it looks for the firstName and lastName properties in the object with which it was bound, i.e. person2.

This is referred to as Explicit Binding.

🤙 call()

The call() method works similarly to bind(), but has one prime difference.

As seen above, the bind() method returns a function that can be invoked later. But the call() method invokes the function and returns the result of that invocation.

Let's see an example:

1. const person = {
2.   firstName: "John",
3.   lastName: "Doe",
4.   sayHi: function (place) {
5.     console.log(`Hello, ${this.firstName} ${this.lastName} from ${place}`);
6.   }
7. };

8. const person2 = {
9.    firstName: "Bob",
10.   lastName: "Builder"
11. };

12. person.sayHi.call(person2, "Earth"); // Hello, Bob Builder from Earth

Consider two objects, person and person2. Here, we are borrowing the sayHi() function of the object person using the call() method, and binding it with the object person2. This is pretty much similar to what we saw in the bind() method.

The call() differs from bind() in the sense that using call(), we can also pass extra parameters to the sayHi() function, along with the object to be bound with.

Here, on line 12, we have passed "Earth" as a parameter to the sayHi() function, which will be stored in the place variable on line 4. You can pass in multiple parameters to the call() method.

The statement on line 12 will invoke the sayHi() function, with the this variable referencing the person2 object and return its result.

👨‍🏭 apply()

The apply() method works similarly to the call() method but has one prime difference.

In the call() method we can pass multiple parameters, but in the apply() method, we have to pass in a single array that would contain all the parameters.

Let's see an example:

1. const person = {
2.   firstName: "John",
3.   lastName: "Doe",
4.   sayHi: function (city, country) {
5.     console.log(`Hello, ${this.firstName} ${this.lastName} from ${city}, ${country}`);
6.   }
7. };

8. const person2 = {
9.   firstName: "Bob",
10.  lastName: "Builder"
11. };

12. person.sayHi.apply(person2, ["Mumbai", "India"]); // Hello, Bob Builder from Mumbai, India

Considering the same two objects person and person2, we are again borrowing the sayHi() function of the person object using the apply() method.

This time, instead of passing parameters in the normal way, we are passing a single array as a parameter to the apply() method. This array will contain all the individual parameters that we wish to pass.

On line 12, we are binding the sayHi() function with the person2 object using the apply() method. The second parameter to the apply() method is an array of strings, which will be passed to the sayHi() function as parameters city and country.

The apply() method will return the result of the invocation.

🔚 Conclusion

  • By default, the methods of an object are implicitly bounded to the object itself, and we can access them using the dot operator.
  • To access the methods of other objects, we need to explicitly bind them to the object using the bind(), call(), or apply() methods, with each one of them having its own use cases.

Thank you for reading. Hope you learned something new. Happy coding!