JavaScripting #1: como utilizar as declarações var, let e const?
Tags: javascript, programming, webdev
Published: 2022-05-01 21:11:40

No início dos meus estudos _mais aprofundados_ em JavaScript, na disciplina de Desenvolvimento Web I, discernir entre os tipos de declarações de variáveis era, certamente, uma das minhas maiores dificuldades. Afinal de contas – e era assim mesmo que eu pensava –, _não é tudo a mesma coisa?_

Adivinha só: não é! E muito disso se baseia nos conceitos de **escopo**. Se em tempos remotos só tínhamos o `var` como declaração de variáveis em **escopos globais** e **de função**, com a chegada do **ECMAScript 6**, lá em 2015, tornou-se possível declarar variáveis com `let` e `const` e também surgiram os **escopos de bloco**, funcionalidades que deixaram o JavaScript mais uniforme e (um pouco) menos sujeito a problemas de segurança.

### 🚨 ...e acho que aqui vale um pequeno adendo sobre o que é um escopo e quais os tipos de escopos que existem:

O **escopo global** se refere a todo o código – ou seja, se você tiver 20 funções diferentes no seu documento de código e declarar uma variável global, é possível utilizar essa variável nessas 20 funções. Assim:

```js
var hello = "Bem-vindo!";

function visitorOne() {
  alert(hello);
}

function visitorTwo() {
  alert(hello);
}

function visitorThree() {
  alert(hello);
}

alert(hello);
```

Já o **escopo local** (ou **de função**) é todo pedaço de código referente a uma função. Ou seja, uma variável de função é toda variável declarada dentro de uma função e que só pode ser acessada dentro dela. Um exemplo:

```javascript
function showComments() {
  let comment = "Muito legal!";
  console.log(comment);
  //Ao acessar essa função, o valor da variável "comment" será mostrado em tela.
}

showComments();
//Muito legal!

function showOtherComments() {
  console.log(comment);
  //Aqui o resultado retornado pela função hideComments será um erro dizendo que a variável não foi definida, pois é impossível acessar a variável "comment", já que é uma variável reservada APENAS ao escopo da função showComments(), logo, será interpretada como se fosse uma variável inexistente.
}

showOtherComments();
//ReferenceError: comment is not defined
```

Por fim, o **escopo de bloco** é qualquer região do código que utilize os famosos "bigodinhos" (ou melhor, chaves), assim como as funções, porém, a diferença esse tipo de escopo é criado por estruturas de controle, tais como as estruturas condicionais `if/else` ou `switch`, de repetição `for` ou `do/while`, entre outros. Por ter essa particularidade, as variáveis declaradas em **escopo de bloco** podem ser acessadas _dentro de toda a função_, e não apenas na estrutura de controle. Tipo isso aqui:

```javascript
function commentPost() {
  //Escopo de função
  let blogPost = "finished";

  if (blogPost === "finished") {
    //Escopo de bloco
    var username = "anewrites";
    alert(`Comenta aí, ${username}! :P`);
  } else {
    alert("Continue lendo <3");
  }

  console.log(blogPost); //finished
  console.log(username); //anewrites
}
```

Agora que já temos uma pequena noção de como cada tipo de escopo funciona, vamos dar uma olhada no que significa cada declaração de variável e como elas podem ser utilizadas dentro de cada tipo de escopo. 👇

## O velho conhecido "var"

Como eu comentei ali no comecinho do post, o `var` era a única declaração de variável global e de escopo de função disponível até a chegada do **ES6** – ou seja, o `var` pode ser declarado globalmente e ser acessado em qualquer região do código, ou ser declarado em escopos de função e acessado apenas nas funções as quais essas variáveis pertencem. Resumidamente, a vantagem de utilizar `var`, pelo menos até a chegada do **ES6**, é diferenciar variável local de variável global.

```js
//Sintaxe:
var varname1 = value1;

//Var declarada de forma global

var posts = 2;

function postCounter() {
  console.log(posts);
}

function postCounter2() {
  console.log(posts);
}

function postCounter3() {
  console.log(posts);
}

postCounter(); //2
postCounter(); //2
postCounter(); //2
console.log(posts); //2

//Var declarada em escopo de função

var name = "Ane";

function postCounter() {
  var numberOfPosts = 2;
  console.log(`${name} fez ${numberOfPosts} posts até agora!`);
}
postCounter(); //Ane fez 2 posts até agora!
console.log(numberOfPosts); //ReferenceError: numberOfPosts is not defined (ao tentar acessar essa variável fora da função, obtemos um erro, pois ela só "existe" dentro da função em que foi declarada)
```

Além dessas duas maneiras de _declarar_ uma `var`, é possível atribuir outro valor à mesma variável. Desta forma:

```js
var posts = 1;
var posts = 2;
console.log(posts); //2
```

### E o hoisting, hein? 🏗️

Eu até falei que é possível atribuir outro valor a uma variável `var`, mas tem algo um tanto _complicado_ sobre fazer isso: o **hoisting**. Derivado do termo _hoist_ em inglês, que significa "levantar" ou "içar" algo, o hoisting faz com que uma `var` seja posicionada no início do contexto de execução no qual ela foi declarada – ou seja, esse mecanismo faz com que as variáveis `var` que você declarou "subam" para o início do seu trecho de código antes mesmo que ele seja executado, algo que faz com que a sua variável, que antes tinha um valor, seja interpretada como `undefined`, mais ou menos assim:

```js
var texto = "dá pra evitar hoisting? D:";
//Variável var global

function writeOnScreen() {
  console.log(texto);
  var texto = "às vezes é inevitável...";
  console.log(texto);
}

writeOnScreen();
//undefined
//às vezes é inevitável...
```

_Mas ué, cadé o primeiro console.log?_

Então, esse é o conceito do **hoisting**. Ao invés de interpretar a variável global e exibi-la em tela, esse mecanismo irá inicializar a variável global lá no início do bloco de função, e só depois é que ela será executada. Pra entender de vez como isso funciona, vamos pensar de acordo com o próprio JavaScript, passo a passo. É assim que esse bloco de função foi executado:

```js
var texto = "dá pra evitar hoisting? D:";
//Variável var global

function writeOnScreen() {
  var texto; //A variável global foi "levantada" durante a execução até o início deste bloco de função
  console.log(texto); //undefined (pois ela só foi declarada aqui dentro, mas não foi definida)
  var texto = "às vezes é inevitável..."; //Valor atribuído pela primeira vez (de acordo com o hoisting) dentro deste bloco de função
  console.log(texto);
}

writeOnScreen();
//undefined
//às vezes é inevitável...
```

Aqui notamos uma das desvantagens de utilizar declarações `var`. Caso ela sofra _hoisting_, será inicializada sempre com um valor `undefined`. E claro, talvez a maior brecha de segurança da utilização do `var` seja a facilidade em redefinir valores para uma declaração `var`, independente do seu escopo de origem, prática que pode vir a causar inúmeros bugs na sua aplicação. Portanto – e essa é uma opinião minha, baseada no que estudei até aqui e ouvi de pessoas desenvolvedoras mais experientes -, com a chegada do **ECMAScript 6**, é possível evitar a utilização do `var`, a não ser que a aplicação em questão seja utilizada em navegadores mais antigos, que não possuam suporte a `let` e `const`.

## A chegada do let

O **ECMAScript 6** trouxe diversas novidades, e uma delas foi a chegada da declaração `let`, uma versão mais consistente de declaração de variáveis e que evita problemas de declaração repetida no mesmo escopo, por exemplo. A seguir, vamos ver algumas das funcionalidades do `let` e como elas podem ser vantajosas para o nosso código:

- O `let` é declarado **apenas em escopos de bloco**, ou seja, qualquer pedaço do código delimitado por chaves (`{}`) e a variável em questão estará disponível _apenas_ neste escopo, dessa forma:

```js
let age = "25";

if (age > 20) {
  let name = "fulano";
  console.log(name); //fulano
}
console.log(name); //name is not defined
```

- O `let` também não permite uma declaração repetida de uma variável como é visto no `var`. É possível atribuir outro valor a uma variável `let`, mas não é permitido declará-la novamente. Por exemplo:

```js
//Atribuição de um novo valor
let bolo = "morango";
bolo = "abacaxi";

console.log(bolo); //abacaxi

//Declaração repetida da variável
let bolo = "morango";
let bolo = "abacaxi"; //Identificador 'bolo' já foi declarado
```

_Porém_, isso é uma regra apenas para declarações de variáveis **no mesmo escopo**. Em escopos diferentes, essa declaração repetida funcionará normalmente, já que o JavaScript interpreta variáveis de escopos diferentes como declarações diferentes.

Acredito que o `let` seja um tanto mais seguro que o `var` nesse sentido. Ao declarar duas variáveis com o mesmo nome, mas em escopos diferentes, por exemplo, não temos o risco de estarmos mexendo na mesma variável, como ocorre em variáveis do tipo `var`.

## Por fim, a variável constante!

É assim que eu gosto de chamar a declaração `const`, pra ser sincera. E, de fato, é mais ou menos isso. O `const` armazena valores _read-only_ que não podem ser alterados, ou seja, que se mantêm constantes. Algumas características do `const`:

- Variáveis declaradas como `const`, assim como `let`, só podem ser acessadas em **escopo de bloco**;

* Meio óbvio, mas é bom reforçar: variáveis `const` não podem ser redefinidas. Ou seja, você não poderá fazer isso:

```js
const suco = "laranja";
suco = "limão"; //TypeError: Atribuição à variável constante.

//E nem isso:

const torta = "limão";
const torta = "banofee"; //Identificador 'torta' já foi declarado
```

- Justamente por ser uma variável constante ( 🤪 ), o `const` precisa ser inicializado com um valor atribuído. Caso contrário, o seguinte erro será mostrado:

```js
const fruta;
 //Missing initializer in const declaration
```

## Certo, mas então qual delas eu devo usar?

Isso vai depender muito de qual aplicação você está desenvolvendo, e para qual browser. Se o seu projeto for direcionado a browsers mais antigos, continue utilizando `var` sem problemas, pois não é garantido que browsers mais antigos forneçam suporte ao **ECMAScript 6**. Do contrário, se estamos falando de variáveis que vão ser alteradas, acredito no `let` como a melhor forma de declarar variáveis mutáveis, ou pelo menos a mais segura e descomplicada. Já para variáveis _read-only_, o `const` é a declaração que fornece maior segurança. :)

Isso é um pouquinho do que sei sobre declaração de variáveis no JavaScript como iniciante no assunto 😉 Caso tenham gostado ou queiram me enviar sugestões, dúvidas ou críticas, fiquem à vontade para comentar esse post ou me chamar lá no twitter [@anestudies](https://twitter.com/anestudies) ;) Até breve!

## Referências
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Grammar_and_types
https://developer.mozilla.org/pt-BR/docs/Glossary/Scope
https://www.alura.com.br/artigos/entenda-diferenca-entre-var-let-e-const-no-javascript
https://walde.co/2016/02/15/javascript-hoisting-o-que-e/