Pílulas de JavaScript: var, let e const

Lari Maza
Lari Maza | PT-BR
Published in
4 min readOct 5, 2018
Photo by Samuel Zeller

[click here for English]

Este é um post de uma série na qual compartilho alguns aprendizados da minha jornada no JavaScript no formato de mini artigos. Veja os posts anteriores no meu perfil!

Temos hoje três palavras-chave para declarar variáveis em JavaScript: var, let e const. A var existe desde o início, enquanto que let e const são adições do ES6. As duas últimas praticamente eliminaram a necessidade do uso de var, que tem se tornado desencorajado. Vamos descobrir por quê!

O principal destaque do uso de const é que esse tipo de variável, como o nome diz, é constante: ela não pode ser redeclarada e o seu valor não pode ser reatribuído (isso não significa que seja imutável; ele ainda pode mudar através de outras manipulações). Por isso, o valor de toda const deve ser atribuído no mesmo statement em que foi declarada, já que não podemos atribuí-lo mais tarde. Veja o que acontece quando tentamos realizar uma reatribuição ilegal:

const juice = 'orange';juice = 'apple';
// Error: Assignment to constant variable

Porém, é bom ressaltar que, não sendo imutável, caso a const guarde um objeto, suas chaves e valores podem ser alterados normalmente:

const myObj = { juice : 'orange' };myObj.juice = 'apple';myObj.juice 
// 'apple'

Outra diferença entre as três é que declarar uma variável global (ou seja, fora de uma função) usando var a adiciona como propriedade do objeto window automaticamente:

var coffee = 'black';window.coffee === coffee
// true

Porém, declarar uma variável global com let ou const não a adiciona ao objeto window:

let tea = 'green';window.tea === tea
// false

Além disso, tanto let quanto const declaram uma variável local no escopo do bloco em que estão inseridas — diferente da var, que ignora o bloco a menos que ele seja uma função. Considera-se que um bloco é qualquer trecho delimitado por chaves {}. Observe um exemplo do comportamento de let no escopo de um bloco de if:

let myNumber = 1;if (myNumber === 1) {
let myNumber = 2;
console.log(myNumber);
// 2
}
console.log(myNumber);
// 1

Se consultado de dentro do bloco if, o valor de myNumber é o que foi atribuído ali dentro: 2. Mas, se consultado de fora do bloco, não temos acesso ao valor que foi atribuído dentro dele, pois a variável fica disponível apenas naquele escopo. Nos resta somente o myNumber de fora, lá da primeira linha: 1.

O mesmo comportamento se aplica à const:

const myNumber = 1;if (myNumber === 1) {
const myNumber = 2;
console.log(myNumber);
// 2
}
console.log(myNumber);
// 1

Essa diferença de escopo afeta também o içamento (hoisting) das variáveis. As variáveis declaradas com var são içadas para o topo do escopo de função em que foram declaradas (ou o escopo global, caso não estejam dentro de nenhuma função). Isso significa que a declaração (por exemplo, var a) é executada antes de qualquer outro código, e antes mesmo da atribuição do valor:

function getMood(isHappy) {
if (isHappy) {
var happy = 'Yay!';
} else {
var meh = 'Meh';
}
}

Na função acima, se analisarmos o içamento das variáveis, é isso que está acontecendo na prática:

function getMood(isHappy) {
var happy, meh;
if (isHappy) {
happy = 'Yay!';
} else {
meh = 'Meh';
}
}

Consegue imaginar como esse comportamento pode retornar muitos undefined acidentais e enxaquecas?

Aí entra uma vantagem das variáveis let e const: por considerarem como escopo o bloco em que foram declaradas, elas têm um comportamento diferente. Se a variável é declarada dentro de um bloco, fica suspensa na "zona morta temporal" até que a declaração seja processada, em vez de ser içada para o topo. Ou seja, a variável só pode ser acessada após a sua declaração. Mais seguro, não é?

Podemos ligar esse contexto a ainda outra particularidade de let e const: elas não podem ser redeclaradas no mesmo escopo e a tentativa retorna um erro de sintaxe. Porém, a redeclaração em escopos diferentes pode ser aceita, porque um contexto não enxerga o outro. Veja um exemplo de código válido com a let foo declarada em dois blocos diferentes:

let myValue = 1;

switch(myValue) {
case 0: {
let foo;
break;
}
case 1: {
let foo;
break;
}
}

Quando usar cada uma delas, então?

A decisão entre let e const depende apenas se você pretende reatribuir o valor dessa variável. O uso de const até melhora a legibilidade do seu código, deixando claro que tal variável é constante.

De modo geral, a contenção em escopos, a possibilidade de impedir a reatribuição do valor e a consequente redução da liberdade no JavaScript (considerada excessiva por alguns) torna o uso de let e const mais aprovado pelos desenvolvedores hoje para evitar alterações e quebras acidentais no código. A convenção geral é de que não há mais motivos para usar var.

Tenha em vista que existem, ainda, outras diferenças e particularidades mais avançadas. Caso queira entrar em detalhes, recomendo que consulte as especificações da MDN para let e para const.

Por hoje é só e até a próxima ❤

--

--