Menu

let, const e var no JavaScript: qual usar e quando

As três formas de declarar variáveis no JavaScript — e por que o código moderno usa const por padrão, let só quando precisa e var praticamente nunca.

Três palavras-chave, uma só missão

Em JavaScript, existem três formas de declarar variáveis: var, let e const. Todas associam um nome a um valor, mas se diferenciam no escopo, nas regras de reatribuição e no comportamento antes da declaração ser executada. No código moderno, usamos const na maior parte das vezes, let quando o valor precisa mudar, e var praticamente nunca.

Resumindo bem rápido:

index.js
Output
Click Run to see the output here.

O restante desta página explica por que essas três linhas se comportam do jeito que se comportam.

const: a escolha padrão

O const cria uma ligação que não pode ser reatribuída. Depois de escrever const x = 5, você não consegue mais fazer x = 6 — o motor do JavaScript vai lançar um TypeError.

index.js
Output
Click Run to see the output here.

Essa é a regra toda. Como a maioria das variáveis num programa bem escrito não precisa ser reatribuída, o const cobre a enorme maioria dos casos. Começar sempre pelo const faz os pontos em que o valor realmente muda ficarem em evidência.

Um ponto que costuma confundir bastante: o const protege a referência, não o valor. Se o valor for um objeto ou array, o conteúdo continua mutável:

index.js
Output
Click Run to see the output here.

const quer dizer "esse nome sempre aponta para esse objeto". Não quer dizer "esse objeto nunca muda". Se você realmente precisa congelar o objeto em si, a ferramenta é Object.freeze(user) — mas, na prática, a maioria do código só segue a convenção de que objetos declarados com const não devem ser mutados.

let: quando você precisa mesmo reatribuir

O let é idêntico ao const em tudo, com uma única diferença: você pode reatribuir o valor. Use-o em contadores, acumuladores, variáveis de laço e em qualquer lugar onde o valor realmente muda ao longo do tempo.

index.js
Output
Click Run to see the output here.

Se você perceber que declarou algo com let mas nunca reatribui aquela variável, troque por const. Em boa parte dos projetos o próprio linter já vai te cutucar pra fazer isso.

Escopo de bloco no JavaScript

Tanto let quanto const têm escopo de bloco. Um bloco é qualquer coisa entre { e } — pode ser o corpo de um if, de um for, de uma função, ou até um bloco solto no meio do código ({ ... }). Uma variável declarada dentro do bloco simplesmente não existe fora dele.

index.js
Output
Click Run to see the output here.

É exatamente isso que você quer. Cada variável fica restrita ao trecho de código onde ela realmente faz sentido, e colisões acidentais de nomes deixam de existir.

O var não funciona assim — e é justamente por isso que vale a pena evitá-lo.

var: escopo de função e armadilhas

O var respeita o escopo da função mais próxima, não do bloco mais próximo. Ou seja, um var declarado dentro de um if ou de um for vaza para o restante da função:

index.js
Output
Click Run to see the output here.

Esse escopo frouxo é a origem de uma lista enorme de bugs clássicos no JavaScript — o mais famoso é aquele loop em que toda iteração compartilha o mesmo var i e, no fim, todos os callbacks enxergam o valor final.

O var também deixa você redeclarar o mesmo nome no mesmo escopo sem reclamar nada, o que acaba mascarando erros de digitação:

index.js
Output
Click Run to see the output here.

O código moderno usa let e const quase o tempo todo. O var ainda aparece em bases de código legadas, respostas antigas do Stack Overflow e em scripts que precisam rodar em ambientes bem antigos.

Hoisting e Temporal Dead Zone no JavaScript

As três formas de declarar variáveis sofrem hoisting — o motor já conhece essas declarações antes de executar o código do bloco —, mas o comportamento antes da linha da declaração é diferente em cada uma.

O var passa por hoisting e já é inicializado com undefined. Por isso, você consegue referenciá-lo antes da linha do var sem tomar erro:

index.js
Output
Click Run to see the output here.

let e const sofrem hoisting, só que sem inicialização. Se você tentar acessá-los antes da declaração, toma um erro na cara. Esse intervalo entre entrar no escopo e chegar na linha da declaração é o que chamamos de temporal dead zone (TDZ):

index.js
Output
Click Run to see the output here.

A TDZ é uma funcionalidade, não um bug. Ela transforma o "usado antes de declarar" de um undefined silencioso em um erro barulhento, o que acaba pegando um monte de erros de digitação e de ordem nas declarações.

Usando const como variável de loop em for...of

Um caso pequeno mas comum: o for...of cria um novo binding a cada iteração, então dá pra usar const na variável do loop mesmo que ela "mude" de uma iteração para outra.

index.js
Output
Click Run to see the output here.

Cada iteração ganha seu próprio binding de name — não existe uma única variável sendo reatribuída. Já um clássico for (let i = 0; i < n; i++) continua precisando de let, porque i é um binding só que vai sendo incrementado.

Uma regra prática para declarar variáveis

Na hora de escolher como declarar, siga esta ordem de preferência:

  • const por padrão. Se o valor não vai ser reatribuído, deixe isso explícito.
  • let quando o binding realmente precisa mudar.
  • var só se você estiver em um código que exige isso.

Aplicando isso de forma consistente, a intenção de cada variável fica óbvia de bater o olho — dá pra saber na hora se ela pode ser reatribuída ou não, e se o escopo é daquele bloco ou da função inteira.

index.js
Output
Click Run to see the output here.

MAX_RETRIES e users nunca mudam — const. successful cresce ao longo do tempo — let. Já user recebe uma nova ligação a cada iteração — const. Lendo o código de cima para baixo, dá pra perceber quais valores mudam e quais ficam fixos sem precisar rodar nada.

Próximo: tipos primitivos

Agora que você sabe declarar variáveis, a pergunta natural é: que tipos de valor elas podem guardar? O JavaScript tem um conjunto enxuto de tipos primitivos — números, strings, booleanos e alguns outros — cada um com suas peculiaridades. É o que vamos ver na próxima página.

Perguntas frequentes

Qual a diferença entre let, const e var no JavaScript?

const e let têm escopo de bloco e foram adicionados no ES2015; var tem escopo de função e é mais antigo. Variáveis declaradas com const não podem ser reatribuídas, já as com let podem. O var também sofre hoisting e é inicializado como undefined, enquanto let e const até passam pelo hoisting, mas não podem ser usados antes da declaração rodar — é a famosa temporal dead zone.

const torna o valor imutável no JavaScript?

Não. O const só impede que você reatribua a variável. Se o valor for um objeto ou array, o conteúdo ainda pode ser alterado normalmente — const user = {}; user.name = 'Ada' funciona sem problema. Se você precisa de imutabilidade de verdade, use Object.freeze ou alguma biblioteca especializada.

Ainda faz sentido usar var no JavaScript moderno?

Quase nunca. let e const têm regras de escopo mais claras e pegam vários bugs já no parse. Os únicos lugares em que você vai esbarrar com var são códigos legados e, de vez em quando, algum script que precisa rodar em ambientes sem suporte a ES2015.

Aprenda a programar com o Coddy

COMEÇAR