Back 2 Basics

What in earth do these .call(), .apply() and .bind() methods do ?

April 18, 2020

sad

Don’t cry! Give it a try :)

Here’s some gossip!

Someone told me, this is one of the first questions asked in an interview for a front end role.

So, let’s jump into it right away!

Who are your favourite actors ?

Mine ? It’s Shah Rukh Khan and Leonardo DiCaprio, obvio!

Let’s create two seperate objects consisting their name and the industry they belong to.

Shah Rukh has an extra feature though (method that logs a statement to the console).

Let’s see how

const actor1 = {
  name: "Shah Rukh Khan",
  wood: "Bollywood",
  printFavourite: function() {
    console.log(`In ${this.wood}, my favourite actor is ${this.name}.`)
  }
}

const actor2 = {
  name: "Leonardo DiCaprio",
  wood: "Hollywood"
}

Done Feuh!!

Now, let’s run :

actor1.printFavourite()

// prints :
//In Bollywood, my favourite actor is Shah Rukh Khan.

What if we wanted to use the printFavourite() method of actor1 for actor2 object, our Leonardo ?

You would ask - Are you stupid ? Is that even possible ?

I’d say - I might sound stupid, but yes, that is possible because this is there.

What’s this this ?

The this keyword of a method refers to the object in which it is defined.

In layman tongue, this is the reference to the outer environment.

And this reference can be changed.

Yaaayy!!

You may read more about this keyword here.

With A Round Of Applause, Let’s Welcome Our Real Heroes : .call(), .apply() and .bind()

clappings

Using .call()


This is how our poor Lenardo(actor2 object) borrows printFavourite method from Shah Rukh(actor1 object) :

actor1.printFavourite.call(actor2)

// prints:
// In Hollywood, my favourite actor is Leonardo DiCaprio.

What have we done ?

We just changed the reference of this keyword from actor1 to actor2 and executed it right away.

That’s what .call() exactly does ie. Changes/adds reference to this keyword and executes the function/method immediately.

It’s now quite reasonable to take the printFavourite method out. Right ?

Let’s do that!

const actor1 = {
  name: "Shah Rukh Khan",
  wood: "Bollywood"
}

const actor2 = {
  name: "Leonardo DiCaprio",
  wood: "Hollywood"
}

const printFavourite = function() {
  console.log(`In ${this.wood}, my favourite actor is ${this.name}.`)
}

Using .apply()


Since, we do not have any external parameter, call and apply would work in an identical way. ie. They will pass the reference to this keyword as the only argument

Let’s see that in action :

// For SRK Fans:
printFavourite.call(actor1)
printFavourite.apply(actor1)

// For DiCaprio Fans:
printFavourite.call(actor2)
printFavourite.apply(actor2)

// prints:
//In Bollywood, my favourite actor is Shah Rukh Khan.
//In Bollywood, my favourite actor is Shah Rukh Khan.
//In Hollywood, my favourite actor is Leonardo DiCaprio.
//In Hollywood, my favourite actor is Leonardo DiCaprio.

Identical! Right ?

identical

Also

We see, that .call() and .apply() excute the function instantly.

Using .bind()


What if we want to pass the reference to this keyword now but excute the function later ?

That’s what .bind() exactly does - Forms a copy of the function binding the this keyword with the argument passed and returns it.

Now, this function can be executed later :

const myFavourite = printFavourite.bind(actor1)
printFavourite.call(actor2)
myFavourite()

// prints :
//In Hollywood, my favourite actor is Leonardo DiCaprio.
//In Bollywood, my favourite actor is Shah Rukh Khan.

Here, actor1 gets bound(in copy of function printFavourite) first, but executed later when we want.

We achieved it using .bind() method.

Woohoo!

done

Passing Arguments


Uptill now, we know that with one argument (reference to the this keyword), there is absolutely no difference between .call() and .apply() methods.

But

This isn’t true!

So now, our favourite actresses would help us figure out the difference.

.call() & .bind()


In these, the first argument passed is the reference to the this keyword.

All the other arguments are passed separated by a comma.

Let’s see how we can do this :

First, we have to modify the function printFavourite() to receive arguments as follows :

const printFavourite = function(actress1, actress2) {
  console.log(`In ${this.wood}, my favourite actor is ${this.name}.
	Among the actresses, I like ${actress1} and ${actress2}.`)
}

Great!

Now, let’s also execute it passing our favourite actresses as arguments :

const myFavourite = printFavourite.bind(actor1, "Kajol", "Deepika Padukone")
printFavourite.call(actor2, "Kate Winslet", "Emma Watson")
myFavourite()

//prints:
//In Hollywood, my favourite actor is Leonardo DiCaprio.
//	Among the actresses, I like Kate Winslet and Emma Watson.

//In Bollywood, my favourite actor is Shah Rukh Khan.
//	Among the actresses, I like Kajol and Deepika Padukone.

Here, we can clearly figure out that the arguments in .call() and .bind() methods are passed in a similar way.

Nice!

The only thing left now is to see how we can pass arguments in .apply()

Why wait ?

.call() & .apply()


The only difference between .call() and .apply() lies in the way we pass arguments.

Here, in .apply(), the first argument is the reference to the this keyword and all the rest of the arguments are passed as an array of arguments.

This is shown below :

printFavourite.call(actor1, "Kajol", "Deepika Padukone")
printFavourite.apply(actor2, ["Kate Winslet", "Emma Watson"])

// prints ;
// In Bollywood, my favourite actor is Shah Rukh Khan.
//	Among the actresses, I like Kajol and Deepika Padukone.
//In Hollywood, my favourite actor is Leonardo DiCaprio.
//	Among the actresses, I like Kate Winslet and Emma Watson.

In the code above, we have passed Kate Winslet and Emma Watson as an array of arguments.

And, the results are similar to the .call() method.

Ergo, Congratulations!

We are done and dusted with .call(), .apply() and .bind() methods.

Hurray!

hurray

Next time you face this question, thank me ;)