Method borrowing in JavaScript.

Method borrowing in JavaScript.

So let's start with what method borrowing in javascript is? where we can use it? and how to do it?

As the name says method borrowing, we can borrow i.e use methods of one object with another object. Suppose we want to use some methods which are present in object A with object B then how we can achieve this. Let's see an example:

const person1 = {
  fullName: "Adarsh Balak",
  printName: function() {
    console.log(this.fullName)
  }
}

const person2 = {
  fullName: 'John Doe'
}

person1.printName()  // Adarsh Balak

Now here person1 can call printName method as its present in that object, but what about person2, if person2 wants to print fullName then it will need printName, so for that javascript provides call(), apply() and bind() methods. Using this we can solve the above problem.

1. call()

Let's see an example:

const person1 = {
  fullName: "Adarsh Balak",
  printName: function() {
    console.log(this.fullName)
  }
}

const person2 = {
  fullName: 'John Doe'
}

person1.printName()  // Adarsh Balak
person1.printName.call(person2)  // John Doe

So what we did is, when printName is called using the call() method and which sets the value of this to person2 so now wherever this is used inside printName method instead of person1 call() sets the this context to the person2. Using the call() method we don't need to create printName in person2 we can just borrow it from a person1. The call() method's first argument is the this ie the object to which we want the method which is called using call() should refer to and others are comma-separated arguments ie call(thisArg, arg1, arg2, ...., argN)

Let's see another example:

const person1 = {
  fullName: "Adarsh Balak",
  printName: function(age, city) {
    console.log(this.fullName, age, city)
  }
}

const person2 = {
  fullName: 'John Doe'
}

person1.printName.call(person2, 22, 'Mumbai')  // John Doe 22 Mumbai

2. apply()

Now the only difference the apply() has is that it takes all the other arguments except the first, in an array-like object ie apply(thisArg, [arg1, arg2, ...argN]). So our method will look like person1.printName.apply(person2, [22, 'Mumbai']).

3. bind()

Now let's understand bind(), so it works similar to call() but instead of calling the method it returns a new function whose this context is bound together with the method onto which the bind() was called. Let's see with a different example:

 function printName(age, city) {
    console.log(this.fullName, age, city)
  }

const person2 = {
  fullName: 'John Doe'
}

const bindedPrintName = printName.bind(person2, 22, 'Mumbai')
bindedPrintName()  // John Doe 22 Mumbai

Now printName is present at a global level rather than inside of an object.

Gotchas with arrow functions

  • For arrow functions the call(), apply() and bind() does not work as expected, because arrow functions do not have their own this, so they inherit this value from the parent context where the arrow function was defined.
  • So when call(), apply() and bind() used with arrow function the first argument ie this context is ignored.
 const printName = (age, city) => {
    console.log(this.fullName, age, city)
  }

const person2 = {
  fullName: 'John Doe'
}

printName.call(person2, 22, 'Mumbai')  // undefined 22 'Mumbai'

Conclusion

  1. call(), apply() and bind() is used to call methods in some other scope, ie when we give the this context with the help of the call, apply and bind what happens is the method behaves as if it was present in that context or object.
  2. call() takes the first argument as thisArgument and the rest as comma-separated values.
  3. apply() also takes the first argument as thisArgument but rests in an array.
  4. bind() works similar to call() instead of calling it returns a new function.
  5. Arrow functions does not work as expected with call(), apply() and bind().

References