DEV Community

Cover image for Hoisting: Que bruxaria é essa?!
ananopaisdojavascript
ananopaisdojavascript

Posted on • Edited on

3 1

Hoisting: Que bruxaria é essa?!

Definição

Hoisting é um comportamento do motor do JS. É quando esse mesmo motor "catapulta" a variável ou função para o topo do escopo. Eu expliquei rapidamente o que é escopo no artigo Var, let e const: Qual é a diferença? e vou deixar o link aqui.

Tentando entender...

Vou usar o console.log() para chamar alguma coisa

console.log(a); // ReferenceError: a is not defined
Enter fullscreen mode Exit fullscreen mode

Como o motor do JS não sabe do que se trata (é variável? é função? é objeto?), retornou um erro dizendo que a não existe. Agora, se eu crio uma variável de mesmo nome a debaixo desse console.log(), o que será que acontece?!

console.log(a); // undefined
var a;
Enter fullscreen mode Exit fullscreen mode

Eu criei uma variável depois do console.log(), não a declarei (não coloquei valor algum nela) e retornou undefined. Por que isso aconteceu?! É porque o motor do JS encontrou essa variável e a jogou para a parte de cima do escopo. É como se eu tivesse criado a variável antes do console.log(), o que não aconteceu.

var a;
console.log(a); // undefined
Enter fullscreen mode Exit fullscreen mode

Mas... e se tivesse declarado um valor em a? O que poderia acontecer?

console.log(a); // undefined
var a = 20;
Enter fullscreen mode Exit fullscreen mode

O resultado seria o mesmo. O retorno seria undefined porque a apareceu antes de ser declarada. O motor do JS entenderia dessa forma:

var a;
console.log(a); // undefined
a = 20;
Enter fullscreen mode Exit fullscreen mode

Ele entenderia que a variável a foi criada sem qualquer valor e que a declaração só apareceu depois de ter sido chamada. Muito louco, não? E se eu colocar o console.log() depois de a já ter sido declarada, o que vai acontecer?

console.log(a); // undefined
var a = 20;
console.log(a); // 20
Enter fullscreen mode Exit fullscreen mode

Hum... nesse caso o valor aparece normalmente. Tudo por conta de var que não tem limitação. Talvez seja uma das razões pelas quais seu uso não é recomendado... E por falar em loucura, que tal testar esse raciocínio com let e const?

Testando com let

Vou fazer a mesma coisa, só que com let no lugar de var. O que será que acontece?!

console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a;
Enter fullscreen mode Exit fullscreen mode

Epa!! A mensagem de erro agora é completamente diferente! Está dizendo que a não pode ser acessada antes da inicialização! Por que isso aconteceu?! A resposta nos leva ao...

Temporal Dead Zone

Parece nome de filme de terror, mas é que essa mensagem de erro é conhecida na comunidade com esse nome (vai entender...). É o seguinte: o motor do JS reconhece que a variável a existe, mas que não pode acessá-la antes da declaração, ou seja, existe uma "zona morta" entre a variável e sua declaração. Lembrando que, apesar de podermos fazer declarações de valores diferentes, let é um pouco mais limitado que var no que se refere ao escopo. Agora vou declarar um valor para a e chamar o console.log() em seguida. O que será que vai acontecer?!

console.log(a); // ReferenceError: Cannot access 'a' before initialization
let a = 123;
console.log(a); // ReferenceError: Cannot access 'a' before initialization
Enter fullscreen mode Exit fullscreen mode

Olha lá! A mensagem de erro permaneceu a mesma! É porque a variável a foi usada antes de ter sido declarada e o motor do JS pode ter entendido que tem muita variável com o mesmo nome e deveria "frear" essa "bagunça". Lembrando: let é mais limitado do que var. O mesmo comportamento se aplica ao const...

console.log(a); // ReferenceError: Cannot access 'a' before initialization
const a = 123;
Enter fullscreen mode Exit fullscreen mode

... e às expressões de funções

console.log(soma(20, 30)); // TypeError: soma is not a function
var soma = function (a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

O que aconteceu? O motor do JS entendeu que a variável soma foi criada primeiro (com valor indefinido) e que só recebeu o seu "valor" (nesse caso, a função) depois. Por isso a mensagem de erro. Como const e let são bem mais limitados, vamos ver o que acontece:

console.log(soma(20, 30)); // ReferenceError: Cannot access 'soma' before initialization
let soma = function (a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode
console.log(soma(20, 30)); // ReferenceError: Cannot access 'soma' before initialization
const soma = function (a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

Acontece exatamente como no caso das variáveis. Essas expressões também não podem ser acessadas antes da inicialização.

E quanto às funções declarativas?!

O comportamento para as funções declarativas será o mesmo das variáveis com var, só que nesse caso vai mostrar o valor declarado na função:

console.log(soma(20, 30)); // 50

function soma(a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

E aí? Gostaram? Até a próxima anotação.

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more