❓ 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):
- bind()
- call()
- 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()
, orapply()
methods, with each one of them having its own use cases.
Thank you for reading. Hope you learned something new. Happy coding!