Variables

Declarações controlam três coisas: scope (escopo, onde a variável existe), mutability (se o valor pode ser alterado depois) e hoisting (içamento, quando a declaração é processada). A escolha errada vaza variáveis para fora do bloco, permite reatribuição acidental e quebra o raciocínio sobre o fluxo.

Dúvida? Use const. Só troque por let quando precisar reatribuir. Nunca use var.

Conceitos fundamentais

ConceitoO que é
const (constante)Declaração de bloco fixa: a referência não pode ser alterada após atribuída
let (deixar / permitir)Declaração de bloco que pode mudar: aceita reatribuição no mesmo escopo
var (variável)Declaração de função (legado): vaza para fora do bloco e permite redeclaração silenciosa
block scope (escopo de bloco)Visibilidade limitada às chaves { } mais próximas
hoisting (içamento)Antecipação da declaração para o topo do escopo na fase de parsing
TDZ (Temporal Dead Zone, Zona Morta Temporal)Trecho entre o início do bloco e a declaração let/const onde acessar a variável lança erro

var: escopo de função, não de bloco

❌ Ruim
if (true) {
  var leaked = 50; // vaza para fora do bloco
}

console.log(leaked); // 50: comportamento inesperado

var count = 10;
var count = 20; // redeclaração silenciosa
✅ Bom
if (true) {
  const contained = 50;
}

console.log(contained); // ReferenceError: escopo correto

let desnecessário

❌ Ruim: let onde const seria suficiente
let MAX_RETRIES = 3; // nunca reatribuído
let userName = "Alice"; // nunca reatribuído
✅ Bom: const por padrão, let só quando necessário
const MAX_RETRIES = 3;
const userName = "Alice";

let attempt = 0;
while (attempt < MAX_RETRIES) {
  attempt++;
}

Mutação direta de objetos

Objetos são passados por referência. Alterar um parâmetro muda o estado do chamador: um efeito colateral invisível e difícil de rastrear. Prefira retornar um novo objeto com as propriedades desejadas.

❌ Ruim: mutação acoplada e difícil de rastrear
function applyDiscount(order) {
  order.discount = 10; // altera o objeto recebido
  order.total -= 10; // efeito colateral escondido
}
✅ Bom: retorna novo estado, sem efeitos colaterais
function applyDiscount(order) {
  const discountedOrder = {
    ...order,
    discount: 10,
    total: order.total - 10,
  };

  return discountedOrder;
}

Evitar valores mágicos

Números e strings soltos no código não dizem nada. Constantes nomeadas tornam a intenção visível.

❌ Ruim: o que significa 18? e 86400000?
if (user.age >= 18) {
  /* ... */
}
if (order.status === 2) {
  /* ... */
}
setTimeout(syncData, 86400000);
✅ Bom: constantes nomeadas
const MINIMUM_DRIVING_AGE = 18;
const ORDER_STATUS_APPROVED = 2;
const ONE_DAY_MS = 86_400_000;

if (user.age >= MINIMUM_DRIVING_AGE) {
  /* ... */
}

if (order.status === ORDER_STATUS_APPROVED) {
  /* ... */
}

setTimeout(syncData, ONE_DAY_MS);

Desenvolvido por @thiagocajadev · Fork baseado no repositório pmndrs/docs · Poimandres.