Aprenda / JavaScript do zero

IntermediárioAula 14 de 1615 min0% da trilha

Imutabilidade, cópia profunda e Map/Set

{ ...objeto } copia só o primeiro nível — um objeto aninhado dentro dele continua sendo a mesma referência nos dois lados.

Você já viu que { ...objeto } resolve o problema de = copiar só a referência. Só que spread tem um limite que costuma surpreender assim que o objeto tem outro objeto dentro dele.

Spread é uma cópia RASA

const usuario = {
  nome: "Ana",
  endereco: { cidade: "Porto Velho" },
};

const copia = { ...usuario };

copia.nome = "Bia";
usuario.nome; // "Ana" — intacto, o primeiro nível foi copiado de verdade

copia.endereco.cidade = "Manaus";
usuario.endereco.cidade; // "Manaus" — mudou também! endereco é a MESMA referência nos dois objetos

{ ...usuario } copia só o primeiro nível de propriedades. Quando uma propriedade é, ela mesma, um objeto ou array, o spread copia a referência pra ela — não o conteúdo. Isso é chamado de cópia rasa (shallow copy), e é a mesma limitação de Object.assign() e de [...array].

structuredClone — cópia profunda de verdade

const copiaProfunda = structuredClone(usuario);

copiaProfunda.endereco.cidade = "Manaus";
usuario.endereco.cidade; // continua "Porto Velho" — copiaProfunda é 100% independente

structuredClone é uma função global (disponível em navegadores modernos e no Node) que copia um objeto recursivamente, nível por nível. Ela não consegue clonar tudo — funções, por exemplo, não sobrevivem ao clone — mas cobre bem a maioria dos casos de dado comum (objetos, arrays, datas, Map, Set).

Map — quando um objeto comum não é suficiente

const contagem = new Map();
contagem.set("maçã", 3);
contagem.set("banana", 5);

contagem.get("maçã");  // 3
contagem.has("uva");    // false
contagem.size;           // 2 — não precisa de Object.keys(obj).length

for (const [fruta, qtd] of contagem) {
  console.log(fruta, qtd);
}

Map faz mais sentido que objeto comum quando a chave não é necessariamente uma string (pode ser um número, um objeto, até uma função), quando você precisa do tamanho direto (.size) ou quando quer ter certeza absoluta da ordem de inserção sem depender de comportamento implícito de objeto.

Set — coleção que garante itens únicos

const idsUnicos = new Set([1, 2, 2, 3, 3, 3]);

idsUnicos.size;    // 3 — duplicados somem sozinhos
idsUnicos.has(2);  // true

[...idsUnicos]; // [1, 2, 3] — fácil converter de volta pra array normal

Set faz mais sentido que array quando o que importa é se um valor existe (e não em que posição), ou quando você precisa remover duplicados sem escrever a lógica de filtro na mão.

Exercício

Dado const idsComDuplicados = [1, 2, 2, 3, 1, 4], produza um array só com os valores únicos, na ordem em que apareceram pela primeira vez.

Quiz rápido

Por que copia.endereco.cidade = 'Manaus' também muda usuario, mesmo copia sendo { ...usuario }?
Quando faz mais sentido usar Set em vez de array puro?