As diferenças entre var, let e const em JavaScript

As diferenças entre var, let e const em JavaScript

Em JavaScript, existem três palavras reservadas usadas para declarar variáveis: var, let e const, sendo que as duas últimas foram implementadas na linguagem na atualização ocorrida em 2015 (ECMAScript 2015 ou ES6, como ficou conhecida esta versão).

const é abreviação de “constant” e é utilizada para declarar variáveis que não terão o seu valor modificado ao longo do código. Já as variáveis declaradas com let podem ter seu valor reatribuído. Ambas surgiram com o objetivo de melhorar alguns comportamentos que a criação de variáveis com var apresenta. Para entender as diferenças no comportamento dos três modos de declaração de variável é necessário conhecer dois importantes conceitos em JavaScript: escopo e hoisting.

Escopo

Toda variável declarada em JavaScript possui um escopo, que pode ser entendido como o espaço dentro do programa onde esta variável pode ser acessada. Antes do ES6 uma variável poderia pertencer ao escopo global, se declarada fora de uma função, ou local, quando declarada dentro de uma função.

Escopo global

Uma variável no escopo global pode ser acessada em qualquer lugar do código:

var country = "Brasil";

function logCountry () {
  console.log(country);
}

logCountry(); // "Brasil"
// A função logCountry consegue acessar a variável global country
// mesmo que esta tenha sido declarada fora dela.

Além disso, se declarada com a palavra reservada var, ela passa a fazer parte do objeto global window:

var country = "Brasil";

console.log(window.country) // "Brasil"

O mesmo não acontece se declarada com let ou const:

let country = "Brasil";
const city = "São Paulo";

console.log(window.country); // undefined
console.log(window.city); // undefined

Escopo local ou escopo da função

Variáveis no escopo local são acessíveis somente dentro da função na qual foram declaradas e por todas as funções declaradas dentro dela:

function logCity() {
  var city = "São Paulo";
  
  function log() {
    console.log(city);    
  }

  log();
}

console.log(city); // Irá gerar erro: ReferenceError
// A variável city não pode ser acessada fora da função logCity.

logCity(); // "São Paulo"

Com a introdução das palavras reservadas let e const, uma nova possibilidade de escopo para a declaração de variável se tornou possível: escopo de bloco.

Escopo de bloco

Em JavaScript, entende-se como bloco tudo o que está compreendido em um par de chaves {}, como um bloco if ou for, por exemplo. Uma variável declarada com var dentro de um bloco não se restringe a este escopo, e sim ao escopo no qual o bloco está inserido:

if(true) {
  var country = "Brasil";
}

console.log(country); // "Brasil"
// A variável country pode ser acessada
// fora do bloco if, mesmo tendo
// sido declarada dentro dele.

A consequência desse comportamento é que se torna possível alterar dentro de um bloco uma variável que tenha sido declarada fora dele, o que, na maioria das ocasiões, é um problema para quem está desenvolvendo.

var i = 10;

for(var i = 0; i < 5; i++) {
  console.log(i); // 0, 1, 2, 3, 4
}

console.log(i); // 5

Em contrapartida, variáveis criadas com let ou const dentro de um bloco pertencem ao escopo deste, sendo assim, no exemplo abaixo, ao sair do bloco if a variável i possui o mesmo valor ao qual a ela foi atribuído antes de entrar no bloco.

let i = 10;

for(let i = 0; i < 5; i++) {
  console.log(i); // 0, 1, 2, 3, 4
}

console.log(i); // 10

Além disso, não é possível redeclarar uma variável com let ou const dentro do mesmo escopo, ao passo que com var este comportamento é permitido.

var name = "Arthur";

var name = "Lucas"; // Isso é permitido
let name = "Valdir"; // Irá gerar erro: SyntaxError
const name = "Maria"; // Irá gerar erro: SyntaxError

Hoisting

Para entender o hoisting é necessário antes ter clara a diferença entre declaração de uma variável e a atribuição de seu valor, vejamos o código abaixo:

var name; // Declaração da variável name
var age = 34; // Declaração + atribuição do valor da variável age

Na primeira linha do exemplo, a variável name é declarada, porém seu valor ainda não foi atribuído. Na segunda linha, a variável age é declarada e na sequência já tem o seu valor atribuído para 34.

Em JavaScript todo código é executado dentro de um contexto, este é processado em duas fases: fase de criação e fase de execução. Na fase de criação a Engine escaneia o código a procura das declarações de variáveis e funções antes que ele seja executado. Enquanto que as funções encontradas já são armazenadas em sua totalidade na memória, as variáveis declaradas com var são armazenadas com o valor undefined. Ao iniciar a fase de execução as funções e variáveis, por já estarem armazenadas, já estão disponíveis para serem usadas, mesmo que suas declarações tenham sido feitas após o local do uso. A este comportamento é dado o nome de hoisting.

É importante observar que, no caso das variáveis declaradas com var, tentar acessá-las antes da atribuição de seu valor não resultará em erro, porém o seu valor irá retorna undefined. Esta é a diferença quando comparada com a declaração de variáveis com let ou const, pois estas não possuem o comportamento de hoisting, portanto, tentar acessá-las antes de serem declaradas irá resultar em erro de referência.

console.log(ocean); // undefined
console.log(continent); // Irá gerar erro: ReferenceError

var ocean = "Pacífico";
let continent = "América do Sul";

Frequentemente hoisting é explicado como a capacidade que a linguagem possui de mover para o topo do escopo as declarações de funções e variáveis deste. Este é um modo didático de explicar o fato de elas estarem acessíveis mesmo antes de terem o seu valor atribuído.

Peculiaridades do const

Além das características apresentadas acima há algumas outras que só pertencem à declaração de variável com const:

  • A variável deve ter o seu valor atribuído no momento da declaração:
const planet; // Isso não é permitido, irá gerar erro: SyntaxError.

const continent = "América do Sul"; // Isto sim é permitido.
  • Uma vez declarada, ela nunca mais poderá ter seu valor reatribuído:
const planet = "Marte";
planet = "Saturno"; // Irá gerar erro: TypeError 
  • Embora não possa ter seu valor reatribuído, é possível modificar o conteúdo de um objeto ou array:
const planet = { name: "Marte" };
planet.color = "red"; // Isso é permitido
console.log(planet); // { name: "Marte", color: "red" }

const planets = ["Marte"];
planets.push("Saturno"); // Isso é permitido
console.log(planets); // [ "Marte", "Saturno" ]

Desde a implementação do ES6, o uso de var se torno obsoleto. const e let são alternativas condizentes com as boas práticas de desenvolvimento em JavaScript e são recomendadas por oferecerem maior controle no comportamento das variáveis e reduzirem erros indesejados no código.

Referências

Categoria: ArtigosTags:
Autor

Gabriel Manussakis

Designer e desenvolvedor front-end. Entusiasta por JavaScript. Atualmente desenvolvendo em Angular e RxJS.