Variáveis em JavaScript: var, let e const na prática
Escopo de bloco contra escopo de função, zona morta temporal e por que const com objeto continua mutável — com o erro real de cada caso no Node.
Variável é um nome dado a um valor guardado na memória. Em JavaScript existem três formas de criar uma, e a escolha entre elas muda o comportamento do programa — não só o estilo.
A regra curta, para você já sair usando: const por padrão, let quando o
valor precisa mudar, var nunca em código novo. O resto deste texto é o
porquê, com o erro de cada caso rodando no terminal.
Três crachás, três regras de acesso
Pense em três crachás para a mesma sala. const deixa você trabalhar com o que
está lá, mas não trocar a sala apontada pelo crachá. let permite apontar para
outro valor quando o programa precisa. var usa uma regra antiga de acesso:
ignora limites de bloco e pode aparecer antes da declaração como undefined.
Os nomes técnicos são declaração, reatribuição e escopo. A analogia
do crachá não quer dizer que const congele objetos; ela trava a ligação do nome
com aquele objeto, não o que existe dentro dele. Antes de entrar nos detalhes,
faça três tentativas: reatribua um const, mude uma propriedade de objeto
guardado em const e leia um let fora do bloco. Os três resultados diferentes
são o mapa desta lição.
O básico
const NOME_DA_LOJA = 'Club Store';
let itensNoCarrinho = 0;
itensNoCarrinho = itensNoCarrinho + 1;
itensNoCarrinho += 2;
console.log(NOME_DA_LOJA, itensNoCarrinho);const cria um nome que não pode ser reapontado. Tentar reatribuir é erro em
tempo de execução:
const CUPOM = 'PRIMEIRACOMPRA';
CUPOM = 'BLACKFRIDAY';Escopo de bloco contra escopo de função
Bloco é qualquer coisa entre chaves: o corpo de um if, de um for, de uma
função. let e const só existem dentro do bloco onde foram declarados.
const total = 250;
if (total > 199) {
let frete = 0;
console.log('frete dentro do if:', frete);
}
console.log('frete fora do if:', frete);Com var, a variável ignora o bloco e sobe para o escopo da função inteira (ou
do módulo, se estiver no topo):
const total = 250;
if (total > 199) {
var frete = 0;
}
console.log('frete fora do if:', frete);Parece conveniente. Não é: significa que uma variável criada dentro de um if
continua viva — e escrevível — pelo resto da função, atropelando qualquer outra
com o mesmo nome.
O caso que mais confunde: var dentro de laço
const precos = [19.9, 49.9, 129.9];
for (var i = 0; i < precos.length; i++) {
setTimeout(() => console.log('var ->', i, precos[i]), 0);
}
for (let j = 0; j < precos.length; j++) {
setTimeout(() => console.log('let ->', j, precos[j]), 0);
}Com var existe uma variável i, compartilhada pelas três funções. Quando
o setTimeout finalmente roda, o laço já terminou e i vale 3 — daí o
undefined, porque precos[3] não existe.
Com let, cada volta do laço ganha o seu próprio j. Cada função guardou um
valor diferente. Se este mecanismo ainda parecer mágico, ele fica claro depois
de funções em JavaScript: o que cada callback guarda
é o escopo em que nasceu.
Zona morta temporal (TDZ)
let e const são içados para o topo do bloco, mas ficam inacessíveis até a
linha da declaração. Esse intervalo é a zona morta temporal.
console.log('estoque atual:', estoque);
let estoque = 12;Repare que a mensagem não é estoque is not defined. O motor sabe que
estoque existe naquele bloco; ele está te dizendo que você chegou cedo demais.
Com var, nada disso acontece — e é aí que mora o problema:
console.log('estoque atual:', estoque);
var estoque = 12;
console.log('estoque depois:', estoque);O programa não quebrou; ele imprimiu undefined e seguiu adiante. Uma hora esse
undefined vira uma conta errada três funções depois, e você vai caçar a causa
no lugar errado. A TDZ do let é uma funcionalidade, não um incômodo: ela
falha no lugar onde o erro foi cometido.
Redeclarar
let e const não deixam você declarar o mesmo nome duas vezes no mesmo
escopo. E este erro é de sintaxe: acontece antes de qualquer linha rodar.
let quantidade = 1;
let quantidade = 2;
console.log(quantidade);Nem o console.log da linha 4 chegou a existir. var aceita a redeclaração em
silêncio, o que é exatamente como dois trechos de código passam a brigar pela
mesma variável sem ninguém perceber.
const com objeto continua mutável
Esta é a confusão mais frequente da lição. const protege o vínculo entre o
nome e o valor, não o conteúdo do valor.
const carrinho = {
cliente: 'Ana',
itens: ['Teclado mecânico'],
};
carrinho.itens.push('Mouse sem fio');
carrinho.cliente = 'Ana Souza';
console.log(carrinho);Nenhum erro. O que const impediria é carrinho = { ... } — apontar o nome
para outro objeto. Mexer por dentro é permitido, e é justamente por isso que a
maior parte do código real usa const para arrays e objetos.
Se você quiser mesmo travar o conteúdo, existe Object.freeze:
const config = Object.freeze({
moeda: 'BRL',
freteGratisAcimaDe: 199,
});
config.freteGratisAcimaDe = 99;
console.log(config.freteGratisAcimaDe);Object.freeze também é raso: ele congela o primeiro nível, não os objetos
aninhados dentro dele.
Nomes
O motor aceita quase qualquer nome; quem lê o código, não. Três hábitos que poupam tempo:
- Nome diz o que é, não o tipo:
precos, nãoarrayDePrecos. - Booleano começa com verbo de estado:
temFreteGratis,estaLogado. - Constante de configuração, definida uma vez e nunca mais tocada, em
MAIUSCULA_COM_UNDERSCORE. Umaconstcomum dentro de função não precisa disso.
const precos = [19.9, 49.9, 129.9];
const total = precos.reduce((soma, preco) => soma + preco, 0);
const freteGratis = total >= 199;
console.log(total.toFixed(2), freteGratis);Resumo
var |
let |
const |
|
|---|---|---|---|
| escopo | função | bloco | bloco |
| içada e acessível antes | sim, como undefined |
não (TDZ) | não (TDZ) |
| reatribuir | sim | sim | não |
| redeclarar no mesmo escopo | sim | não | não |
A próxima lição da trilha de JavaScript é sobre funções — onde escopo deixa de ser teoria e passa a decidir o que cada pedaço do seu código consegue enxergar. O guia completo de JavaScript mostra a trilha inteira em ordem.
Prefere aprender em vídeo?
Tem uma aula sobre este assunto no nosso canal.
Perguntas frequentes
Ainda preciso aprender var?
Qual a diferença entre não definida e undefined?
Se const não impede alterar o objeto, para que serve?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- MDN — Grammar and types: Declarations — developer.mozilla.org
- ECMAScript 2026 Language Specification — Let and Const Declarations — tc39.es



