Hoisting em JavaScript
O Hoisting é o processo de acessar variáveis antes de sua definição. Isso pode parecer estranho, mas é uma característica do compilador JavaScript. A compilação do código ocorre em duas passagens. Na primeira passagem, o compilador coleta todas as declarações de variáveis e identificadores, sem executar código ou chamar métodos. Na segunda passagem, ocorre a execução do código. Assim, mesmo que uma variável seja definida após o seu uso, não haverá erro, pois o compilador já conhece todas as variáveis desde a primeira passagem.
É como se o código com a definição de variáveis e funções fosse "erguido" para cima antes de seu uso. Essa "elevação" é conhecida como hoisting.
Variáveis var
As variáveis var, que são afetadas pelo hoisting, recebem por padrão o valor undefined. Por exemplo, considere o seguinte código simples:
console.log(foo);Sua execução resultará em um erro de ReferenceError: foo is not defined (foo não está definida).
Vamos adicionar a definição da variável:
console.log(foo); // undefined
var foo = "Tom";Neste caso, o console exibirá o valor undefined. Na primeira passagem, o compilador reconhece a existência da variável foo e atribui a ela o valor undefined. Na segunda passagem, o método console.log(foo) é chamado.
Outro exemplo:
var c = a * b;
var a = 7;
var b = 3;
console.log(c); // NaNAqui, ocorre a mesma situação. As variáveis a e b são usadas antes de serem definidas. Por padrão, recebem o valor undefined. Multiplicar undefined por undefined resulta em NaN (Not a Number).
O mesmo se aplica a funções. Podemos chamar uma função antes de defini-la:
display();
function display() {
console.log("Hello Hoisting");
}Neste caso, recebemos um erro de TypeError: display is not a function (display não é uma função). Na primeira passagem, o compilador encontra a variável display e atribui a ela o valor undefined. Na segunda passagem, ao tentar chamar a função, o compilador percebe que não há nada para chamar, resultando em um erro.
Variáveis let e const
O hoisting para variáveis let e const é diferente: elas não recebem valores padrão. Vimos que as variáveis var recebem undefined por padrão. Agora, vejamos o que acontece com uma variável let:
console.log(foo); // Uncaught ReferenceError: Cannot access 'foo' before initialization
let foo = "Tom";
console.log(foo); // Não será executadoAqui, obtemos um erro de Uncaught ReferenceError: Cannot access 'foo' before initialization (Não é possível acessar 'foo' antes da inicialização).
Isso é diferente de uma variável let declarada, mas não inicializada:
let foo; // Por padrão, foo = undefined
console.log(foo); // undefined
foo = "Tom";
console.log(foo); // TomUma variável let não inicializada tem o valor undefined por padrão, e não resultará em erro.
O mesmo vale para const:
console.log(foo); // Uncaught ReferenceError: Cannot access 'foo' before initialization
const foo = "Tom";
console.log(foo); // Não será executadoAqui, obtemos um erro de Uncaught ReferenceError: Cannot access 'foo' before initialization (Não é possível acessar 'foo' antes da inicialização).
Isso mostra a diferença no comportamento de hoisting para variáveis var, let e const.