Arrow function em JavaScript: sintaxe e o this
A arrow function é curta, mas abriu mão de this, arguments, prototype e new. Cada ausência explicada com código executado no Node e o erro que ela provoca.
Arrow function é uma expressão de função escrita com a seta =>. Ela reduz a
sintaxe de callbacks e funções curtas, mas não é apenas uma abreviação de
function: não cria this, arguments ou prototype próprios e não pode ser
chamada com new.
Pense em dois tipos de crachá. Uma função tradicional recebe o crachá de quem a
chamou; é daí que pode vir seu this. Uma arrow não emite um crachá novo: ela
continua usando o this do ambiente em que foi criada. Tecnicamente, esse
comportamento se chama this léxico. Ele resolve o contexto de muitos
callbacks, mas torna a arrow inadequada como método que depende do objeto à
esquerda do ponto.
Essas ausências são parte do desenho da linguagem. Por isso, a escolha entre
arrow e function depende do contexto de execução, não apenas da quantidade de
caracteres.
Esta lição continua a de function expression contra declaration — arrow é uma expression, e tudo que vale para expression vale para ela: não é içada, precisa existir antes de ser chamada, e é um valor que você guarda.
Da forma longa à forma curta
Quatro escritas da mesma ideia, do mais verboso ao mais enxuto:
const comFunction = function (preco) {
return preco * 1.18;
};
const arrowLonga = (preco) => {
return preco * 1.18;
};
const arrowCurta = (preco) => preco * 1.18;
const semParametro = () => 'Club Store';
const doisParametros = (preco, quantidade) => preco * quantidade;
console.log(comFunction(100), arrowLonga(100), arrowCurta(100));
console.log(semParametro(), doisParametros(89.9, 3).toFixed(2));Duas regras da sintaxe: sem parâmetro nenhum, os parênteses vazios são obrigatórios; com dois ou mais, também. Só o caso de um parâmetro permite omitir — e mesmo assim vale manter, porque o dia em que você acrescentar o segundo parâmetro não vai precisar mexer nos parênteses. A maioria dos guias de estilo, incluindo o padrão do Prettier, mantém os parênteses sempre.
Retorno implícito
Sem chaves, o valor da expressão já é o retorno — não se escreve return. É o
que deixa cadeias de array legíveis:
const precos = [19.9, 49.9, 129.9, 289.9];
console.log(precos.map((preco) => Number((preco * 1.18).toFixed(2))));
console.log(precos.filter((preco) => preco >= 100));
console.log(precos.reduce((soma, preco) => soma + preco, 0).toFixed(2));
console.log(precos.some((preco) => preco > 250), precos.every((preco) => preco > 10));No momento em que você abre chaves, o corpo vira um bloco comum e o return
volta a ser obrigatório. Esquecer disso produz uma função que devolve
undefined sem reclamar — o mesmo silêncio que a lição de
parâmetros e retorno documenta.
Devolver objeto exige parênteses
Aqui está o erro de sintaxe característico da arrow. A chave depois da seta é ambígua: o motor precisa decidir se ela abre um corpo de função ou um objeto literal, e ele sempre escolhe corpo de função.
const itens = [
{ nome: 'Teclado mecânico', preco: 289.9 },
{ nome: 'Mouse sem fio', preco: 149.9 },
];
const etiquetas = itens.map((item) => { nome: item.nome, preco: item.preco });
console.log(etiquetas);SyntaxError: Unexpected token ‘:’ at compileSourceTextModule (node:internal/modules/esm/utils:318:16) at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:90:18)
Node.js v24.16.0
Repare em duas coisas. O acento circunflexo aponta para o segundo dois
pontos, não para a chave: o motor tinha lido nome: item.nome como um rótulo
seguido de expressão — sintaxe válida dentro de um bloco — e só engasgou no
preco: seguinte. E o rastro não tem nenhuma linha do seu código depois da
primeira: é erro de compilação, não de execução. Nada do arquivo rodou.
A correção é envolver o objeto em parênteses:
const itens = [
{ nome: 'Teclado mecânico', preco: 289.9 },
{ nome: 'Mouse sem fio', preco: 149.9 },
];
const etiquetas = itens.map((item) => ({
nome: item.nome,
comDesconto: Number((item.preco * 0.9).toFixed(2)),
}));
console.log(etiquetas);A arrow não tem this próprio
Esta é a diferença que importa. Uma function recebe this de quem a
chamou; uma arrow herda o this do lugar onde foi escrita, e ninguém
consegue mudar isso depois.
No topo de um módulo ES, this é undefined — e é esse undefined que uma
arrow escrita ali herda:
console.log('this no topo do módulo:', this);
const ondeEstou = () => this;
console.log('this herdado pela arrow:', ondeEstou());A consequência prática aparece dentro de objetos. Como callback, a arrow é exatamente o que você quer; como método, é exatamente o que você não quer:
const pedido = {
cliente: 'Ana Souza',
itens: [
{ nome: 'Teclado mecânico', preco: 289.9 },
{ nome: 'Mouse sem fio', preco: 149.9 },
],
etiquetasComArrow() {
return this.itens.map((item) => `${this.cliente} — ${item.nome}`);
},
etiquetasComFunction() {
return this.itens.map(function (item) {
return `${this.cliente} — ${item.nome}`;
});
},
};
console.log(pedido.etiquetasComArrow());
console.log(pedido.etiquetasComFunction());TypeError: Cannot read properties of undefined (reading ‘cliente’) at file:///private/tmp/loja/arrow-this-callback.mjs:14:22 at Array.map (<anonymous>) at Object.etiquetasComFunction (file:///private/tmp/loja/arrow-this-callback.mjs:13:23) at file:///private/tmp/loja/arrow-this-callback.mjs:20:20 at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
Node.js v24.16.0
Os dois métodos são idênticos, tirando a forma do callback interno. O da arrow
funcionou porque ela herdou o this do método etiquetasComArrow, que apontava
para pedido. O da function quebrou porque map chama o callback sem dono, e
em modo estrito isso significa this === undefined.
Antes de 2015 a gente resolvia isso guardando var self = this no começo do
método — const também não existia ainda — ou passando this como segundo
argumento de map. A arrow tornou os
dois desnecessários. Os detalhes das quatro regras que decidem o this de cada
chamada estão em this em JavaScript.
A arrow não tem arguments — mas enxerga o de fora
Uma arrow no topo do arquivo que use arguments dá ReferenceError, porque o
nome não existe em lugar nenhum. Dentro de uma function, o efeito é mais
sutil: a arrow enxerga o arguments da função que a contém.
function aplicarPromocao(percentual) {
const listar = () => Array.from(arguments).slice(1);
return { percentual, produtos: listar() };
}
console.log(aplicarPromocao(15, 'Teclado mecânico', 'Mouse sem fio'));Funcionou — e é justamente o tipo de coisa que confunde quem lê depois, porque a arrow parece estar acessando os próprios argumentos e não está. Escreva com rest, que é explícito e funciona igual nas duas sintaxes:
const aplicarPromocao = (percentual, ...produtos) => ({ percentual, produtos });
console.log(aplicarPromocao(15, 'Teclado mecânico', 'Mouse sem fio'));
console.log(aplicarPromocao(30));A arrow não pode ser chamada com new
Função construtora precisa de duas coisas que a arrow não tem: um this próprio
para o objeto novo e um prototype de onde herdar métodos.
const Produto = (nome, preco) => {
this.nome = nome;
this.preco = preco;
};
const teclado = new Produto('Teclado mecânico', 289.9);
console.log(teclado);TypeError: Produto is not a constructor at file:///private/tmp/loja/arrow-new.mjs:6:17 at ModuleJob.run (node:internal/modules/esm/module_job:439:25)
Node.js v24.16.0
A ausência do prototype dá para conferir na mão:
function ProdutoNormal(nome) {
this.nome = nome;
}
const ProdutoArrow = (nome) => ({ nome });
console.log('prototype normal:', typeof ProdutoNormal.prototype);
console.log('prototype arrow: ', typeof ProdutoArrow.prototype);
console.log(Object.getOwnPropertyNames(ProdutoNormal));
console.log(Object.getOwnPropertyNames(ProdutoArrow));Uma arrow tem duas propriedades; uma function tem três. Essa propriedade a
mais é a diferença inteira entre poder e não poder construir objetos. Hoje isso
raramente importa, porque construtor virou class — e class também não aceita
arrow no lugar de constructor.
Onde usar e onde não usar
| lugar | arrow? | motivo |
|---|---|---|
callback de map, filter, reduce |
sim | curta, e o this herdado é o que você quer |
| callback dentro de método de objeto | sim | resolve a perda de contexto sem bind |
| método de objeto ou de classe | não | precisa do this de quem chamou |
| função construtora | não | não aceita new, não tem prototype |
listener de DOM que usa event.currentTarget |
depende | com arrow, this não é o elemento; use o parâmetro do evento |
function* (generator) |
não | não existe arrow generator |
A regra prática: arrow quando você quer que o this de fora entre; function
quando você quer que o this de dentro venha da chamada. Toda vez que a
resposta for “não uso this aqui”, as duas servem — e aí escolha a mais curta.
Para verificar, crie um objeto contador com dois métodos: normal() { return this === contador } e arrow: () => this === contador. Chame os dois. O método
tradicional deve devolver true; a arrow, false, porque não recebe
contador como this. Explique o resultado pelo lugar em que cada função
obteve seu contexto.
A próxima lição desta trilha mostra o lugar onde a arrow mais aparece:
função callback em JavaScript. Se a
mensagem Cannot read properties of undefined já apareceu no seu terminal por
causa de this, o
guia desse erro
cobre as outras três origens dele.
Perguntas frequentes
Posso escrever todo o meu código só com arrow function?
Por que a arrow precisa de parênteses para devolver um objeto?
Arrow function é mais rápida que function?
Arrow function pode ser async?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- MDN — Arrow function expressions — developer.mozilla.org
- MDN — this — developer.mozilla.org
- ECMAScript 2026 — Arrow Function Definitions — tc39.es


