Pílulas de JavaScript: call e apply

Lari Maza
Lari Maza | PT-BR
Published in
3 min readOct 2, 2018
Photo by William Krause

[click here for English]

Este é um post de uma série na qual compartilho alguns aprendizados da minha jornada no JavaScript no formato de mini artigos. Veja os posts anteriores no meu perfil!

call() e apply() são dois métodos bem similares utilizados para fornecer um valor de this específico para uma função. Eles tornam possível determinar o contexto de onde ela será executada.

Ambos podem ser invocados diretamente de uma função. Passamos como argumento o objeto que queremos utilizar como valor de this, além dos outros argumentos que a função recebe, se há algum. Considere a função e o objeto abaixo:

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

Se quisermos aplicar a função sayHello ao contexto do objeto user1, podemos fazer isso com call(). Não chamaremos a função sayHello()! Apenas faremos referência a ela pelo nome e depois usaremos a notação de ponto para invocar o método de função call(), passando como argumento o objeto user1, que é o valor de this que queremos usar. Vamos testar tudo isso na prática:

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

Note onde está o par de parênteses responsável por fazer a invocação: o método call() é que executa a função, olhando para dentro do objeto user1 para buscar o valor de this.name. Nesse momento, a expressão this.name é substituída por user1.name , que por sua vez é substituída por 'Paula'.

Agora, vamos tornar as coisas um pouco mais interessantes! Vamos testar o call() em uma função que recebe argumentos:

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

Além de passar o objeto user1 novamente como valor de this, agora passaremos também o parâmetro recebido pela função commentHobby na lista de argumentos de call(). Observe:

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

O resultado é exatamente o mesmo; o método call() chamou a função commentHobby usando user1 como o valor de this. Dessa vez, porém, passamos também a string 'love' para substituir o argumento opinion.

E se tentarmos usar o método call() em uma função que está dentro de um objeto — ou seja, um método? Sim: nós podemos pegar emprestado um método de um objeto e aplicá-lo para outro objeto!

Vamos criar um objeto kitty e um objeto puppy:

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

Se testarmos o método greet como está, o valor de this é o objeto kitty e, portanto, this.race é substituído pelo seu valor 'cat':

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

Mas, supondo que precisamos aproveitar o método greet para aplicar a puppy, podemos acessá-lo dentro do objeto kitty e então usar call() para invocá-lo no objeto puppy:

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

A esse ponto, você pode estar se perguntando: mas e o apply()? Bem, o apply() tem a exata mesma utilidade: chamar uma função aplicando o valor de this fornecido, mais quaisquer outros parâmetros necessários. A diferença é que, em vez de parâmetros separados por vírgula, o apply() recebe os parâmetros adicionais da função em um array.

Vamos testá-lo em uma função com mais de um parâmetro:

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

Vejamos o que acontece se utilizarmos o apply() para aplicar a função sayWhere ao contexto do objeto user2, passando também os argumentos recebidos por sayWhere em um array:

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

O uso é bem similar, não é? Quando devemos escolher call() ou apply(), então?

Isso dependerá do tipo de argumentos necessários na função que desejamos utilizar. O apply() é especialmente útil quando a função recebe muitos argumentos ou, ainda, quando não temos certeza de quantos argumentos exatamente ela receberá.

Por hoje é só e até a próxima ❤

--

--