Expressões de Função em JavaScript
JavaScript oferece diversas formas de definir funções, sendo as Declarações de Função e as Expressões de Função duas das mais fundamentais.
Introdução às Expressões de Função em JavaScript
JavaScript oferece várias formas de definir funções, e duas das mais fundamentais são as declarações de função e as expressões de função. Uma expressão de função permite tratar uma função como qualquer outro valor: você pode armazená-la em uma variável, passá-la para outra função ou retorná-la de uma. Saber exatamente como as expressões diferem das declarações — especialmente em relação ao hoisting — vai te livrar de uma classe de bugs confusos.
Esta página aborda a sintaxe das expressões de função, por que elas se comportam de forma diferente das declarações, expressões nomeadas, os usos práticos mais comuns (callbacks, IIFEs, manipuladores de eventos, código assíncrono) e como tudo isso se conecta às modernas arrow functions.
Expressões de Função: Sintaxe e Uso
O que é uma Expressão de Função?
Uma expressão de função define uma função como parte de uma expressão maior — tipicamente o lado direito de uma atribuição. A função em si é apenas um valor, e a variável à qual você a atribui se torna o meio pelo qual você a chama. Esta é a forma mais básica:
Compare isso com uma declaração de função, que começa com a palavra-chave function como uma instrução independente:
Ambas produzem um greet chamável, mas são processadas pelo motor em momentos diferentes — o que é exatamente o tema da próxima seção.
Hoisting: a diferença fundamental
Declarações de função são içadas (hoisted): o motor as lê durante a fase de compilação, então a função existe antes da linha onde está escrita. Você pode chamá-la mais cedo no arquivo. Expressões de função não são — o valor da função só é atribuído quando a execução chega àquela linha, portanto chamá-la muito cedo falha:
Nota: Com var, o nome greet é içado, mas seu valor é undefined até que a atribuição seja executada, então chamá-lo cedo lança um TypeError ("greet is not a function"). Com let ou const, o nome fica na temporal dead zone e você obtém um ReferenceError. De qualquer forma, a regra é a mesma: defina uma expressão de função antes de usá-la.
Características das Expressões de Função
- Funções anônimas: Expressões de função frequentemente são anônimas — a função não tem nome próprio e é referenciada por meio da variável.
- Armazenadas em variáveis: A função é um valor, então ela vive em uma variável (ou elemento de array, propriedade de object, etc.).
- Cidadãs de primeira classe: Em JavaScript, funções são valores de primeira classe — podem ser passadas como argumentos, retornadas de outras funções e atribuídas a variáveis.
- Expressões de função nomeadas: Uma expressão pode ter seu próprio nome (ex.:
let fn = function myFunc() {}). O nome é visível apenas dentro da função, o que melhora os rastreamentos de pilha e permite que a função chame a si mesma. - Arrow functions: Código moderno frequentemente usa arrow functions (
() => {}) como uma forma mais curta de expressão, embora elas tratem othisde forma diferente.
Expressões de Função Nomeadas
Dar a uma expressão um nome interno permite que a função se referencie de forma confiável — útil para recursão — mesmo que a variável externa seja reatribuída posteriormente:
Aplicações Práticas das Expressões de Função
Funções de Callback
O uso mais comum de uma expressão de função é como callback — uma função passada para outra função e executada posteriormente, após a conclusão de alguma operação. Passar a função inline como uma expressão mantém a lógica exatamente onde é usada:
IIFE (Expressão de Função Invocada Imediatamente)
Uma IIFE é uma expressão de função que é executada no momento em que é definida. Os parênteses ao redor transformam a função em uma expressão, e os () finais a chamam imediatamente. Esta era a forma clássica de criar um escopo privado e evitar que variáveis vazassem para o escopo global:
Nota: Hoje em dia, let/const com escopo de bloco e módulos ES cobrem a maior parte do que as IIFEs eram usadas para fazer, então você as verá menos em código novo — mas ainda são comuns em bibliotecas antigas e scripts empacotados.
Expressões de Função vs Declarações de Função
| Declaração de Função | Expressão de Função | |
|---|---|---|
| Sintaxe | function f() {} como uma instrução | let f = function () {} dentro de uma expressão |
| Hoisting | Totalmente içada — chamável antes de sua linha | Não chamável antes de a atribuição ser executada |
| Nomeação | Sempre nomeada | Frequentemente anônima (pode ser nomeada) |
| Ideal para | Utilitários de nível superior usados em todo o arquivo | Callbacks, IIFEs, definições condicionais |
Uma regra prática: use uma declaração para uma função independente e reutilizável, e uma expressão quando a função é um valor que você está prestes a passar para algum lugar ou definir condicionalmente.
Exemplos Avançados e Casos de Uso
Manipulação de Eventos
No navegador, expressões de função são a forma natural de anexar manipuladores de eventos, já que você passa a função diretamente para addEventListener:
document.getElementById('myButton').addEventListener('click', function () {
console.log('Button clicked!');
});Programação Assíncrona
Com Promises e async/await, expressões de função oferecem uma forma concisa de passar unidades de código. Aqui, uma expressão de função trata cada valor resolvido:
Conclusão
Dominar as Expressões de Função em JavaScript é fundamental para escrever código eficiente e fácil de manter. Sua flexibilidade, aliada ao poder das capacidades de programação funcional do JavaScript, as torna uma ferramenta indispensável no arsenal de qualquer desenvolvedor.
Lembre-se de que a escolha entre uma Expressão de Função e uma Declaração de Função depende dos requisitos específicos do seu código e do contexto em que você está trabalhando. Continue praticando e explorando esses conceitos para aprofundar sua compreensão e proficiência em JavaScript.