Arrow Functions em JavaScript
Aprenda como as arrow functions do JavaScript funcionam em profundidade: this lexical, sem arguments ou super próprios, por que não podem ser construtores e quando não usá-las em métodos de objeto.
Introdução às Arrow Functions do JavaScript
As arrow functions, introduzidas no ES6 (ECMAScript 2015), são hoje um recurso essencial do JavaScript, oferecendo uma forma mais simples de escrever expressões de função. Elas são especialmente populares porque simplificam o código e ajudam a resolver problemas comuns com a palavra-chave this.
Esta página vai além da sintaxe (abordada em Arrow functions, o básico) e explora o porquê do comportamento das arrow functions. A versão resumida é que uma arrow function não possui seus próprios vínculos. Ela não recebe seu próprio this, seus próprios arguments, seu próprio super, nem um método [[Construct]]. Sempre que você referencia qualquer um desses elementos dentro de uma arrow, o JavaScript os busca no escopo circundante (lexical), exatamente como faria com qualquer variável comum. Quase todas as peculiaridades e vantagens das arrow functions derivam dessa única regra.
Definindo Arrow Functions
As arrow functions permitem uma sintaxe mais curta em comparação com as expressões de função tradicionais. Veja uma comparação básica:
A versão com arrow function não é apenas mais curta, mas também elimina a necessidade da palavra-chave function e das chaves quando há uma única expressão.
Variações de Sintaxe
As arrow functions podem ser escritas de várias formas, dependendo do número de parâmetros e da complexidade do corpo da função:
- Sem Parâmetros: Use parênteses vazios:
- Parâmetro Único: Os parênteses são opcionais:
- Múltiplos Parâmetros: Os parênteses são obrigatórios:
- Múltiplas Linhas: Use chaves e um
returnexplícito (se retornar um valor):
Arrow Functions Não Possuem this Próprio
A propriedade mais importante das arrow functions é que elas não recebem seu próprio this. Uma função regular determina seu this no momento da chamada, com base em como é invocada (abordado em Métodos de objeto, "this"). Uma arrow function ignora tudo isso e lê o this do escopo onde foi definida — isso é chamado de this lexical.
É exatamente isso que você quer quando uma arrow é usada como callback. Um método que perde seu this dentro de um callback comum o mantém dentro de uma arrow:
Substitua a arrow por uma function(member) { ... } comum e o this dentro do forEach se tornará undefined, gerando Cannot read properties of undefined. Antes das arrow functions, os desenvolvedores contornavam isso com const self = this; ou .bind(this) — veja Vinculação de funções. As arrow functions eliminam a necessidade desses truques.
A mesma regra lexical resolve o clássico problema com timers, onde um callback é executado desconectado do seu objeto:
Como o this é fixado de forma lexical, você não pode alterá-lo. Chamar .call(), .apply() ou .bind() em uma arrow function não tem efeito sobre o this — o vínculo é ignorado:
Arrow Functions Não Possuem arguments
As arrow functions também não possuem um objeto arguments próprio. Referenciar arguments dentro de uma arrow acessa a função envolvente — o que é útil para wrappers e decoradores:
Se você realmente precisa dos argumentos da própria arrow function, use parâmetros rest (...args), que funcionam em qualquer lugar:
Arrow Functions Não São Construtíveis
Como uma arrow function não possui o método interno [[Construct]] nem a propriedade prototype, você não pode usá-la com o operador new:
Pelo mesmo motivo, as arrow functions não podem referenciar super para acessar uma classe pai, portanto nunca são usadas como construtores de classe ou métodos de classe que dependem de super.
Quando Não Usar Arrow Functions
O this lexical é ótimo em callbacks, mas inadequado em alguns contextos comuns. Use uma função regular quando a função precisar do seu próprio this dinâmico.
Métodos de Objeto
Quando uma função é o método de um object, normalmente você quer que o this aponte para esse object. Uma arrow pega o this do escopo externo (frequentemente o escopo do módulo ou global), então não verá as propriedades do próprio object:
Use a forma abreviada de método regular (ou uma expressão function) para métodos de object. Veja Métodos de objeto, "this" para o panorama completo.
Métodos de Prototype e Construtores
Como as arrows não são construtíveis e não possuem this próprio, elas não podem definir métodos de prototype nem servir como funções construtoras. Métodos adicionados a um prototype devem ser funções regulares para que cada instância resolva o this para si mesma.
Manipuladores de Eventos do DOM (no navegador)
Quando você anexa um manipulador com addEventListener, o navegador o chama com this definido como o elemento que recebeu o evento. Uma arrow ignora isso e mantém o this externo, portanto use uma função regular se precisar que o this seja o elemento (você sempre pode usar event.currentTarget de qualquer forma).
Técnicas Avançadas
Retornando Literais de Object
Para retornar um literal de object a partir de uma arrow function, envolva o object em parênteses:
IIFE com Arrow Functions
As arrow functions podem ser usadas em Expressões de Função Invocadas Imediatamente (IIFE):
Resumo
As arrow functions são melhor compreendidas pelo que lhes falta. Elas possuem:
- Nenhum
thispróprio — é obtido do escopo circundante (thislexical), e.call/.apply/.bindnão podem alterá-lo. Ideal para callbacks, inadequado para métodos de object. - Nenhum
argumentspróprio — use parâmetros rest (...args) se precisar deles. - Nenhum
super— portanto, não podem ser métodos de classe que chamam um pai. - Nenhum
[[Construct]]e nenhumprototype— portanto, não podem ser usadas comnewnem como métodos de prototype.
Use arrows para callbacks curtos e qualquer função que deva manter o this externo. Use funções regulares para métodos de object, métodos de prototype, construtores e manipuladores de DOM que precisam de um this dinâmico.
Capítulos Relacionados
- Arrow functions, o básico
- Métodos de objeto, "this"
- Vinculação de funções
- Construtor, operador "new"
- Parâmetros rest e sintaxe spread