JavaScript Pills: call and apply

Lari Maza
Lari Maza | En
Published in
3 min readOct 15, 2019
Photo by William Krause

[clique aqui para português]

This is a post from a series where I share insights from my journey with JavaScript in a mini article format. See all other posts on my profile!

call() and apply() are very similar methods both used to pass a specific value of this to a function. They make it possible to determine the context from which the function will be executed.

Both methods can be invoked directly from a function. As an argument, we pass the object we want to use as the value of this; we may also pass other arguments that the function receives, if any. Consider the function and the object below:

function sayHello() {
console.log('Hello, ' + this.name);
}
const user1 = {
name: 'Paula',
hobby: 'witchcraft'
}

If we want to apply the sayHello function to the context of the user1 object, we can do so with call(). We will not call the sayHello() function! We'll just reference it by name and then use dot notation to invoke the call() function method, passing the user1 object as an argument, which is the value of this we want to use. Let’s test this:

sayHello.call(user1);// 'Hello, Paula'

Observe where the parentheses responsible for making the invocation are: the call() method executes the function, looking inside the user1 object to find the this.name value. At this point, the expression this.name is replaced by user1.name, which in turn is replaced by 'Paula'.

Now, let’s make things a little more interesting! Let’s test call() on a function that takes arguments:

function commentHobby(opinion) {
console.log('I ' + opinion + ' ' + this.hobby);
}
const user1 = {
name: 'Paula',
hobby: 'witchcraft'
}

In addition to passing the user1 object again as the value of this, now we'll also pass the argument received by the commentHobby function to the call() argument list. Observe:

commentHobby.call(user1, 'love');// 'I love witchcraft'

The result is exactly the same; the call() method invoked the commentHobby function using user1 as the value of this. This time, however, we also passed the 'love' string to replace the opinion argument.

What if we tried to use the call() method on a function that's inside an object — that is, a method? Yes: we can borrow a method from an object and apply it to another one!

Let’s create the kitty object and the puppy object:

const kitty = {
race: 'cat',
color: 'white',
greet: function() {
console.log("Hi, I'm a " + this.race);
}
}
const puppy = {
race: 'dog',
color: 'black'
}

If we test the greet method as it is now, the value of this is the kitty object and therefore this.race is replaced with its value 'cat':

kitty.greet();// "Hi, I'm a cat"

But if we have to borrow the greet method to apply to the puppy object, we can access the method from within the kitty object and use call() to invoke it in the puppy object:

kitty.greet.call(puppy);// "Hi, I'm a dog"

At this point you may be asking: but what about apply()? Well, apply() has the exact same role: to call a function using the provided value of this, plus any other arguments if applicable. The difference is that, instead of comma-separated arguments, apply() receives the additional function arguments in an array.

Let’s test it in a function with more than one argument:

function sayWhere(city, country) {
console.log ('I am ' + this.name + ' from ' + city + ', ' + country);
}
const user2 = {
name: 'Lola'
}

Let's see what happens if we use apply() to apply the sayWhere function to the context of the user2 object, while also passing the arguments received by sayWhere in an array:

sayWhere.apply(user2, ['Paris', 'France']);// 'I am Lola from Paris, France'

The use is very similar, isn’t it? When should we choose call() or apply(), then?

This depends on the type of arguments required in the function we want to use. apply() is especially useful when a function takes many arguments, or yet when we are not sure how many arguments exactly it will receive.

That’s all for today and see you next time ❤

--

--