Objeto Function e Expressões de Função Nomeadas (NFE) em JavaScript
Aprenda que funções em JavaScript são objetos: leia as propriedades name e length, adicione propriedades personalizadas e use Expressões de Função Nomeadas (NFE) para auto-referência confiável e recursão.
Funções São Objetos
Em JavaScript, toda função é um object. Esse único fato explica muito do comportamento que, de outra forma, parece mágico: você pode passar uma função como qualquer valor, armazená-la em uma variável, ler propriedades dela e até adicionar suas próprias propriedades a ela.
Você já cria funções o tempo todo com declarações e expressões de função. Este capítulo analisa o que uma função é depois de criada: um object com propriedades internas úteis (name e length), a capacidade de armazenar propriedades personalizadas e uma forma especial — a Expressão de Função Nomeada — que permite a uma função se referenciar de forma confiável.
Esta página pressupõe que você está familiarizado com Expressões de Função. Se let f = function() {...} é algo novo para você, leia isso primeiro.
A Propriedade name
Toda função tem uma propriedade name que armazena o nome da função como uma string. A parte inteligente é que o JavaScript a preenche mesmo quando não há um nome no lugar óbvio — um comportamento chamado nomenclatura contextual.
O motor analisa a atribuição e copia o nome da variável para a função anônima. Isso também funciona para parâmetros padrão e métodos de object:
Porém, não existe mágica que funcione sempre. Se não há nome e nenhuma fonte de onde copiar um — por exemplo, uma função criada dentro de um array — name é uma string vazia:
A propriedade name é útil para logging e depuração: um rastreamento de pilha que diz at sayHi é muito mais útil do que at <anonymous>.
A Propriedade length
A propriedade length de uma função retorna o número de parâmetros que ela declara em sua definição. Parâmetros rest (...rest) e parâmetros com valores padrão não são contados, e a contagem para no primeiro desses parâmetros.
Um uso real comum de length é introspectar um callback. Algumas bibliotecas chamam um handler de forma diferente dependendo de quantos argumentos ele espera — por exemplo, tratando um handler sem argumentos como "executar uma vez para todos" e um handler com um argumento como "executar uma vez por item".
Propriedades Personalizadas
Como uma função é um object, você pode adicionar suas próprias propriedades a ela. Isso é diferente de uma variável local: uma propriedade vive na função e sobrevive entre chamadas, sendo uma maneira organizada de dar a uma função seu próprio estado persistente.
Um exemplo clássico é um contador de chamadas:
Uma propriedade de função não é o mesmo que uma variável dentro da função. Uma variável local é redefinida a cada chamada; uma propriedade persiste, e também é legível e gravável externamente, o que a torna útil para configuração (como armazenar resultados em cache na própria função).
Expressões de Função Nomeadas (NFE)
Uma Expressão de Função Nomeada é uma expressão de função que carrega um nome após a palavra-chave function:
let sayHi = function func(who) {
console.log("Hello, " + who);
};Isso parece incomum — por que dar um nome a algo já atribuído a sayHi? O nome func aqui é especial de duas formas:
- Ele permite que a função se referencie de forma confiável a partir do seu próprio corpo.
- Ele é visível apenas dentro da função — você não pode chamar
func()externamente.
Por que o nome interno importa
Você pode pensar que poderia usar a variável externa sayHi para auto-referência. O problema é que a variável externa pode mudar. Com uma NFE, o nome interno sempre aponta para a função atual, independentemente do que aconteça com a variável:
Se a função tivesse chamado sayHi("Guest") em vez de func("Guest"), a chamada lançaria um TypeError porque sayHi foi definido como null. O nome interno é imune a isso.
NFE e recursão
Essa auto-referência é exatamente o que a recursão precisa. Uma NFE mantém uma chamada recursiva funcionando mesmo que a função seja posteriormente reatribuída ou passada com outro nome — veja Recursão e Pilha em JavaScript para o panorama completo.
Observe que o truque do nome interno se aplica apenas a Expressões de Função. Uma Declaração de Função não pode ter um nome interno separado e não tem como ocultar um nome do escopo externo, portanto não pode manter uma auto-referência privada da mesma forma.
Quando Usar Esses Recursos
- Use
namepara logs mais claros e saída de depuração. - Use
lengthao escrever bibliotecas que se adaptam à aridade de um callback. - Use propriedades personalizadas para dar a uma função estado persistente (contadores, caches, configuração) sem um closure envolvente ou uma variável global.
- Use uma Expressão de Função Nomeada sempre que uma expressão de função precisar se chamar — especialmente para recursão ou handlers destacáveis — para que a chamada sobreviva à reatribuição de variáveis.
Resumo
Uma função JavaScript é um object que você pode inspecionar e estender. A propriedade name fornece seu nome (muitas vezes preenchido contextualmente), length informa a contagem de parâmetros declarados e você pode adicionar propriedades personalizadas para estado persistente. Uma Expressão de Função Nomeada adiciona um nome interno exclusivo que permite a uma função se chamar de forma confiável, sendo a maneira mais segura de escrever expressões de função auto-referenciais e recursivas.