call e apply em JavaScript: Principais erros e como evitá-los
Você já olhou para o código de outra pessoa em JavaScript e viu construções estranhas como func.call(this, arg1, arg2) ou func.apply(this, [arg1, arg2])? E se perguntou: "Qual é, afinal, a diferença?" Se sim — você não está sozinho. A pergunta "What is the difference between call and apply?" é uma das mais populares no Stack Overflow com centenas de milhares de visualizações. E não é por acaso.
A confusão entre call e apply é uma armadilha clássica para iniciantes (e não só). Neste artigo, não vamos apenas explicar a teoria. Vamos analisar o top 5 erros reais, mostrar como corrigi-los e dar um algoritmo claro que vai acabar para sempre com a sua confusão. Vamos nessa!
Breve introdução: o que são call e apply?
Antes de mergulharmos nos erros, vamos refrescar a base. Os métodos call e apply são métodos nativos de funções em JavaScript. Sua principal tarefa é indicar explicitamente o contexto de chamada (this) para a função. Em outras palavras, eles permitem dizer: "Ei, função, imagine que você está trabalhando com este objeto".
Sintaxe:
func.call(context, arg1, arg2, ...);func.apply(context, [arg1, arg2, ...]);Diferença chave:
callrecebe os argumentos separados por vírgula (lista).applyrecebe os argumentos na forma de um array (ou objeto array-like).
É só isso. Esta é a única diferença. Mas é justamente por causa deste "detalhe" que surge a maioria dos erros. Vamos analisá-los.
Top 5 erros ao trabalhar com call e apply
Erro nº1: Confusão com a lista de argumentos (o mais comum!)
Este é o "rei" de todos os erros. Você escreveu uma função que espera argumentos um por um, mas passou um array usando call. Ou vice-versa.
Exemplo-catástrofe:
function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation);}
const user = { name: 'Ana' };
// Erro: passamos um array, mas usamos callgreet.call(user, ['Olá', '!']); // Saída: "Olá,! Ana,undefined" — uma completa bagunça!Por que isso acontece? O call espera argumentos um por um. Ele recebeu um único argumento — um array inteiro — e o colocou na variável greeting. A variável punctuation ficou como undefined.
Como corrigir? Use apply se os dados já estiverem em um array:
greet.apply(user, ['Olá', '!']); // Saída: "Olá, Ana!" — correto!Ou espalhe o array com o operador spread (abordagem moderna):
greet.call(user, ...['Olá', '!']); // Também funciona!Erro nº2: Esquecer que apply funciona com objetos array-like
Muitos pensam que apply aceita apenas um array verdadeiro. Na verdade, ele aceita qualquer objeto array-like (objeto semelhante a um array): ele deve ter uma propriedade length e chaves numéricas.
Exemplo:
function sum() { let total = 0; for (let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total;}
// Passamos não um array, mas um objeto com lengthconst args = { 0: 5, 1: 10, 2: 15, length: 3 };
console.log(sum.apply(null, args)); // Saída: 30 — funciona!Mas tenha cuidado: se o objeto não tiver length, o apply simplesmente o ignorará. Este é um erro comum ao trabalhar com arguments (objeto obsoleto) ou com NodeList.
Erro nº3: Usar call/apply onde uma chamada simples seria suficiente
Às vezes, iniciantes abusam do uso de call e apply.