Variáveis em ES6

Let, const e var. Como funcionam e qual delas usar?

Posted by Raphael Lima on 20-01-2017

Var

Até a versão anterior do JavaScript, a ES5, declaravamos variáveis através da palavra-chave var, que eram chamadas de variáveis de escopo de funções. O escopo do JavaScript é dado por funções e não por blocos e a palavra-chave var garantia a variável dentro de todo o escopo de onde ela foi declarada, ou seja, poderia ser acessada de qualquer ponto dentro do nosso código. Agora que já sabemos como funciona a declaração de variáveis com var, vamos ver em código:

function foo() {
  if(1 == 2) {
    var x = 1;
  }
  console.log(x);
}

Executando o código acima a saída é…? Isso mesmo! undefined! Ué, mas porque? O escopo de var não é de função? Sim! Isso mesmo. Undefined não quer dizer que a váriavel não existe, mas sim que ela não possui nenhum valor e como a atribuição de valor depende do resultado de uma condição e esta por sua vez é falsa, a atribuição não chega a acontecer, mas a engine JavaScript sabe que em algum ponto do código foi definida uma variável x. Vejamos um outro exemplo:

var a = 1;
function bar() {
  console.log(a);
  var b = 2;
  if(true) {
    var c = 3;
    console.log(b);
  }
  console.log(c);
}

bar(); //Saída -> 1, 2, 3

No código acima, podemos ver que a variável c é acessível fora do bloco if, a b acessada de dentro do bloco ìf e a variável a, declarada fora da função foi acessada dentro de bar().

Let

Quando a ES6 foi lançada, trouxe consigo diversas features e dentre elas a palavra-chave let, que é usada para declarar variáveis com escopo de bloco. Seu comportamento é idêntico a var quando declarada fora de uma função, ou seja, ela fica acessível no escopo global. Mas quando declarada dentro de qualquer bloco seja ele uma função, um if ou um loop, ela fica acessível apenas dentro do bloco (e sub-blocos) do qual foi declarada. Vamos reescrever o mesmo exemplo anterior, só que agora usando a key let:

let a = 1; //Acessível globalmente
function bar() {
  console.log(a);
  let b = 2; //Acessível apenas dentro de `bar()` e sub-blocos.
  if(true) {
    let c = 3; //Acessível apenas dentro do bloco `if`
    console.log(b);
  }
  console.log(c);
}

bar(); //Saída -> 1, 2 e ReferenceErrorException: c is not defined

No código acima, as variáveis a e b tem seus valores escritos na console corretamente, mas c não. Isso se dá pois estamos tentando acessar uma váriavel fora do bloco do qual ela pertence. Mesmo o if sendo declarado dentro da função bar() a variável c só é acessivel dentro dele mesmo. O contrário é permitido, conforme podemos observar com a variável b que foi declarada dentro da função e é acessada de dentro do bloco if, mas tenha cuidado, isso só é possível se o bloco estiver dentro da mesma função da qual foi a variável foi declarada.

Além disso, uma outra particularidade envolve a key let que é a redeclaração de variáveis. Quando declaramos uma variável duas vezes no mesmo escopo com var, o último valor é o que prevalece, vejamos um exemplo:

var variavel = 0;
var variavel = 10;
console.log(variavel); // Saída -> 10

function funcao() {
  var outra_variavel = 20;
  var outra_variavel = 30;
  console.log(outra_variavel);
}

funcao(); //Saída -> 30

Com let esse comportamento é diferente, ou seja, quando tentamos declarar no mesmo escopo uma variável com let que já está declarada, é gerada uma Type e Syntax Error dizendo que a váriavel já foi definida. Exemplo:

let variavel = 0;
let variavel = 10; //TypeError: Identifier 'variavel' has already been declared

function funcao() {
  let outra_variavel = 20;
  let outra_variavel = 30; //SyntaxError: Identifier 'outra_variavel' has already been declared
}

Isso não significa que não podemos ter variáveis com o mesmo nome, podemos. Desde que não estejam no mesmo escopo. Se não estiverem, a engine JS as interpreta como variáveis diferentes, devido dentro da função ou bloco ser criado um novo escopo. Exemplo:

var a = 10;
let b = 20;
function bar() {
  var a = 30; //Outra variável
  let b = 40; //Outra variável
  if(true) {
    var a = 50; //Sobrescreve o valor de `a` dentro de `bar()`
    let b = 60; //Outra variável
    console.log(a); //Saída -> 50
    console.log(b); //Saída -> 60
  }
  console.log(a); //Saída -> 50
  console.log(b); //Saída -> 40
}
bar();
console.log(a); //Saída -> 10
console.log(b); //Saída -> 20

Const

Além de let a ES6 trouxe também a palavra-chave const. Esta é usada para declarar variáveis read-only, isto é, a variável não pode ter seu valor reatribuido, ou seja, seu estado é imutável. Assim como let variáveis do tipo const também são variáveis de escopo de bloco. Tente executar o código do primeiro exemplo de let e veja o resultado.
A const veio para nos prover uma proteção nativa para constantes, pois, antes disso era utilizada a seguinte convenção var const_var = 123., mas isso não era garantia de que esse valor não seria mudado no decorrer do programa. Após a introdução de const podemos declarar constantes const variavel = “valor”; e assim temos a certeza de que esse será seu único e imutável valor.

Mas… E aí? var ou let? Qual devo usar?

Bom, se você irá escrever seu todo seu código em ES6 (lembre-se: nem todas as features da ES6 são suportadas pelos browsers. Use um transpiler, babel é uma boa opção), é recomendado usar let, pois assim você conseguirá previnir alguns bugs causados por erros de escopos e também o deixará mais fácil de ler. Não escreve partes com var e partes com let, ou um ou outro. Por outro lado, se você já está habituado com var e isto não te causa problemas, então continue usando.