Pílulas de JavaScript: var, let e const
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 ❤