Talvez você já tenha escrito uma função e a chamado antes da linha em que ela foi declarada. Funcionou, não foi? Isso não é mágica, é hoisting. Em JavaScript, hoisting é o comportamento padrão de mover as declarações para o topo do escopo antes da execução do código. Ou seja, o interpretador "eleva" as declarações, mas não os valores. Isso explica por que uma variável pode existir antes da sua atribuição, mas com valor undefined.
O que exatamente é elevado?
Quando o JavaScript executa um código, ele passa por duas fases: criação e execução. Na fase de criação, o motor reserva espaço para as declarações de variáveis e funções. É isso que chamamos de hoisting. Para funções declaradas com function, a declaração inteira é elevada, incluindo o corpo. Para variáveis com var, apenas a declaração é elevada, não a atribuição.
Um exemplo ajuda a clarear. Se você escreve:
console.log(nome); var nome = "Maria";
O JavaScript interpreta como:
var nome; console.log(nome); // undefined nome = "Maria";
Perceba: a variável existe, mas o valor ainda não foi atribuído. Isso gera o clássico undefined, não um erro. Com funções, o comportamento é diferente. A declaração inteira é elevada, então você pode chamar a função antes de escrevê-la.
Como let e const se comportam?
Aqui a história muda. let e const também sofrem hoisting, mas de forma mais restrita. Eles são elevados, porém ficam em uma "zona morta temporal" até a linha da declaração. Se você tentar acessar uma variável let ou const antes da declaração, recebe um ReferenceError.
console.log(idade); // ReferenceError: Cannot access 'idade' before initialization let idade = 30;
A variável existe no escopo, mas não pode ser usada antes da inicialização. Isso é uma proteção do JavaScript para evitar erros silenciosos. Na prática, o hoisting com let e const existe, mas você não consegue observá-lo sem gerar erro.
E as funções? Sempre são elevadas?
Funções declaradas com function são elevadas por completo. Por isso, a chamada antes da declaração funciona. Mas atenção: funções atribuídas a variáveis seguem a regra da variável. Se você usa const funcao = () => {}, o hoisting segue o comportamento do const, ou seja, não pode chamar antes da linha.
Um detalhe importante: o hoisting acontece por escopo. Em uma função, as declarações internas são elevadas para o topo daquela função, não para o escopo global. Isso evita que variáveis locais "vazem" para fora.
Como evitar erros comuns?
A melhor prática é declarar todas as variáveis no topo do escopo, mesmo que sem valor inicial. Isso torna o código mais previsível. Prefira const para valores que não mudam e let para os que mudam. Evite var em código novo, já que o hoisting com var pode gerar confusão com o undefined.
Outro cuidado: não dependa do hoisting para organizar o código. Ele é um comportamento da linguagem, não uma recomendação de estilo. Escrever a declaração antes do uso é mais legível e evita sustos.
Resumo rápido
Hoisting é o JavaScript "elevando" declarações para o topo do escopo. Funções declaradas com function são elevadas por inteiro; var é elevada sem valor; let e const são elevadas, mas ficam inacessíveis até a inicialização.
Perguntas frequentes
O que é hoisting em JavaScript?
Hoisting é o comportamento do JavaScript de mover as declarações de variáveis e funções para o topo do seu escopo antes da execução do código. Isso permite que funções sejam chamadas antes da declaração, mas variáveis com var ficam com valor undefined até a atribuição.
Qual a diferença entre hoisting de var e let?
Com var, a declaração é elevada e a variável fica acessível com valor undefined antes da atribuição. Com let, a declaração também é elevada, mas a variável fica em uma zona morta temporal, gerando ReferenceError se acessada antes da linha de declaração.
Hoisting funciona com arrow functions?
Não da mesma forma. Arrow functions são atribuídas a variáveis, então seguem o comportamento da variável usada. Se for const, não pode ser chamada antes da declaração. Se for var, a variável é elevada, mas a função não está atribuída ainda, gerando erro.
Hoisting acontece em todos os escopos?
Sim, o hoisting acontece em qualquer escopo, seja global, de função ou de bloco. As declarações são elevadas para o topo do escopo onde estão, não para fora dele. Variáveis declaradas dentro de uma função não são acessíveis fora dela.
Por que hoisting causa erro com let e const?
Porque let e const têm uma zona morta temporal. A declaração é elevada, mas o acesso antes da inicialização é bloqueado. Isso é intencional: evita erros silenciosos e incentiva declarar antes de usar.
Como evitar problemas com hoisting?
Declare todas as variáveis no topo do escopo e use const por padrão, let quando precisar reatribuir. Evite var. Isso torna o código mais previsível e reduz a chance de encontrar undefined inesperado.