Diferenças entre funções normais e Arrow Functions em JavaScript: quando usar cada sintaxe
(jrsinclair.com)- As declarações de função em JavaScript podem ser feitas de várias formas, como declaração com a palavra-chave
function, expressão de função e arrow function - Declarações de função passam por hoisting, então podem ser referenciadas em qualquer ponto do código
- Arrow functions têm como vantagem a sintaxe concisa, mas apresentam diferenças importantes, como não terem vinculação própria de this/arguments/super
- Funções construtoras, generators e métodos não são casos adequados para uso de arrow functions
- Para callbacks simples ou funções anônimas, as arrow functions são mais apropriadas
Function Declarations, Function Expressions, and Arrow Functions
- Em JavaScript, é possível definir funções de três formas: declaração de função (statement), expressão de função (expression) e arrow function
- A declaração de função faz a vinculação direta do nome, como em
function isVowel(chr) { ... }, e pode ser referenciada em qualquer lugar do código (hoisting). Em stack traces e durante a depuração, o nome da função aparece de forma clara - A expressão de função é a forma de atribuir uma função anônima a uma variável, como em
const takeWhile = function(predicate, arr) { ... } - Também é possível dar um nome interno a uma expressão de função, mas esse nome não é vinculado ao escopo externo e é usado principalmente para rastrear erros em stack traces
Hoisting and Naming
- Declarações de função são içadas (hoisted) pelo mecanismo do JavaScript, então funcionam mesmo se forem chamadas antes da declaração
- Expressões de função anônimas só podem ser chamadas depois da atribuição à variável
- Para depuração, dar um nome explicitamente à função pode ser vantajoso nos stack traces
Arrow Functions
- Sintaxe curta e concisa: escritas na forma
(parâmetros) => { ... }, sem a palavra-chavefunction - São sempre funções anônimas (embora possam ser atribuídas a variáveis e usadas como se tivessem nome)
- Só podem ser usadas como expressão (expression), não como statement
- Não têm vinculação própria de this/arguments/super: diferente das declarações/expressões de função, elas capturam o this do escopo externo
- No caso de uma única expressão, é possível omitir chaves e
return; se houver apenas 1 parâmetro, os parênteses também podem ser omitidos - Não podem ser usadas como construtoras: arrow functions não podem ser chamadas com a palavra-chave new e não funcionam como funções construtoras
- Não podem ser generators: não é possível usar yield, então não dá para criar funções generator com elas
- Exemplos de código:
const sum = (a, b) => a + b; const square = x => x * x;
Exemplo prático: this, construtores e generators
- É apresentado um exemplo da diferença de comportamento do
thisentre funções normais e arrow functions- Ao usar como método dentro de um objeto, uma função normal faz com que
thisaponte para o próprio objeto, enquanto uma arrow function aponta paraundefinedou para othisdo escopo externo
- Ao usar como método dentro de um objeto, uma função normal faz com que
- Ao definir uma função construtora como arrow function, ocorre um
TypeError - Funções generator obrigatoriamente precisam usar a sintaxe
function*
Que sintaxe de função escolher e quando?
- Se você precisa de generator (uso de yield) → use
function* - Se precisa usar this → use a palavra-chave
functionou um método de classe - Se precisa de hoisting ou quer melhor legibilidade em nível mais alto → use declaração de função
- Se nenhuma dessas condições se aplica → arrow functions são vantajosas por deixarem o código mais conciso
Conclusão
- Em JavaScript, a sintaxe da função deve ser escolhida de acordo com o objetivo, a necessidade de
thise se ela será construtora ou generator - Para callbacks do dia a dia e funções simples, arrow functions são a melhor escolha
- Para métodos de objeto, construtores e generators, é necessário usar a sintaxe com
function - Se você precisa de hoisting ou de mais liberdade na ordem das declarações, a declaração de função é mais vantajosa
3 comentários
Tão fundamental quanto isso também é a presença ou ausência de
prototype...E também a forma de referenciar as funções de ordem superior que são geradas ...
const a = (a: () => null): (() => () => null) =>() => a
() => ❤️