Hoisting: Como evitar erros comuns de referência em JavaScript
Tags: braziliandevs, javascript, webdev, beginners
Published: 2023-03-02 20:27:11

Hoisting é um comportamento do JavaScript que muitos desenvolvedores iniciantes têm dificuldade de entender. É um conceito que tem relação com a forma como as declarações de variáveis e funções são interpretadas pela _engine_ do JavaScript. Neste artigo, vamos discutir o que é hoisting, como ele funciona e suas implicações no JavaScript.

## O que é Hoisting?

Hoisting é o processo que ocorre no JavaScript onde o interpretador "eleva" todas as **declarações** de variáveis e funções para o topo do escopo atual antes da execução do código. No entanto, é importante entender que as declarações de variáveis e funções não são fisicamente movidas para o topo do código, mas sim colocadas na memória durante a fase de compilação, permanecendo exatamente onde você as digitou.

Em outras palavras, quando você executa um código JavaScript, o interpretador primeiro analisa todo o código para procurar por declarações de variáveis e funções. Ele então reserva espaço na memória para essas declarações, tornando-as disponíveis antes mesmo de serem declaradas no código. Isso significa que você pode chamar uma função ou variável antes de serem declaradas, pois o interpretador já as carregou na memória.

Vejamos um exemplo simples:

```javascript
console.log(x); // undefined
var x = 5;
```

Neste exemplo, a variável `x` é declarada depois que ela é usada, mas mesmo assim não recebemos um erro. Isso ocorre porque o interpretador do JavaScript move a declaração da variável para o topo do escopo atual durante a fase de compilação, o que significa que a variável já está definida quando o código é executado. No entanto, o valor da variável ainda não foi atribuido, e é por isso que o `console.log(x)` retorna `undefined`.

## Variáveis em Hoisting

Quando se trata de variáveis, o hoisting afeta as declarações de variáveis feitas com a palavra-chave _var_. A palavra-chave _var_ é a mais antiga e foi usada para declarar variáveis no JavaScript antes do ECMAScript 2015. As variáveis declaradas como _var_ possuem escopo global ou de função e são içadas (hoisted).

Isso significa que a declaração da variável é movida para o topo do escopo atual antes da execução do código. No entanto, apenas a declaração é movida para o topo, não a atribuição do valor. Como resultado, se uma variável for utilizada antes de ser declarada e inicializada, seu valor será `undefined`.

```javascript
console.log(name); // Output: undefined
var name = 'Joel';
console.log(name); // Output: 'Joel'
```

Por outro lado, a palavra-chave _let_, introduzida no ECMAScript 2015, possui comportamento semelhante ao _var_ quanto ao hoisting, mas com escopo de bloco. Isso significa que as variáveis declaradas como _let_ só são visíveis dentro do bloco em que foram declaradas. Além disso, as variáveis declaradas como _let_ não podem ser redeclaradas no mesmo escopo.

```javascript
console.log(name); // Uncaught ReferenceError: name is not defined
let name = 'Joel';
console.log(name); // Output: 'Joel'
```

Já a palavra-chave _const_, também introduzida no ECMAScript 2015, possui escopo de bloco como _let_, mas não permite reatribuição de valor. Uma vez que uma variável é inicializada como _const_, seu valor não pode ser modificado. É possível, no entanto, modificar as propriedades ou elementos do objeto ou array.

```javascript
const name = 'Joel';
name = 'Maria'; // Uncaught TypeError: Assignment to constant variable.

// Embora não possamos reatribuir a constante "person", podemos modificar a propriedade "age" do objeto que ela referencia.

const person = { name: 'Joel', age: 23 };
person.age = 31;

console.log(person); // Output: { name: 'Joel', age: 31 }

// Mesmo que a variável "numbers" seja uma constante, podemos modificar o conteúdo do array usando métodos como push().

const numbers = [1, 2, 3];
numbers.push(4);

console.log(numbers); // Output: [1, 2, 3, 4]
```

## Funções em Hoisting

O hoisting afeta as funções da mesma maneira que afeta as variáveis no JavaScript. Durante o processo de compilação do código, todas as declarações de funções são movidas para o topo do escopo atual antes da execução do código, permitindo que elas sejam usadas antes mesmo de serem declaradas. No entanto, apenas a declaração da função é movida para o topo, não a atribuição de valor, o que significa que não é possível chamar uma função anônima antes de sua declaração.

```javascript
sayHello(); // Output: 'Hello!'

function sayHello () {
  console.log('Hello!');
}

sayHi(); // Uncaught TypeError: sayHi is not a function

let sayHi = function () {
  console.log('Hi!');
}
```

Neste exemplo, uma função anônima é atribuída à variável `sayHi` com a palavra-chave _let_. No entanto, como a atribuição de valor não é içada, a tentativa de chamar a função _sayHi()_ antes de sua declaração resulta em um `TypeError`.

Portanto, é importante entender a diferença entre as palavras-chave _var_, _let_ e _const_ e como o hoisting afeta cada uma delas, bem como as funções em JavaScript, para escrever um código mais seguro e evitar erros de referência. Além disso, é recomendado declarar todas as variáveis e funções antes de sua utilização, para evitar confusão e facilitar a leitura e manutenção do código.