Desafio JavaScript

Cópia rasa e aninhada

Enunciado

Crie uma função clonarSuperficial que recebe um objeto e retorna uma cópia rasa usando spread. Em seguida, crie clonarProfundo que também copia objetos aninhados (apenas um nível de profundidade). Demonstre que a cópia rasa compartilha referências aninhadas, enquanto a profunda não. Use JSON.parse(JSON.stringify()) para a cópia profunda? Não, implemente manualmente com spread e verificação de tipo.

Requisitos

  • clonarSuperficial usa spread para copiar o objeto
  • clonarProfundo copia o primeiro nível e também os objetos aninhados (um nível)
  • Demonstrar que alterar um objeto aninhado na cópia rasa afeta o original, mas na profunda não
  • Imprimir os resultados

Código inicial

function clonarSuperficial(obj) {
  // seu código aqui
}

function clonarProfundo(obj) {
  // seu código aqui
}

// Teste
const original = { a: 1, b: { c: 2 } };
const copiaRasa = clonarSuperficial(original);
const copiaProfunda = clonarProfundo(original);

copiaRasa.b.c = 99;
copiaProfunda.b.c = 100;

console.log(original.b.c); // 99 (afetado pela rasa)
console.log(copiaRasa.b.c); // 99
console.log(copiaProfunda.b.c); // 100

Saída esperada

99
99
100
Ver dica

Para a cópia profunda, itere sobre as chaves e, se o valor for um objeto (não nulo, não array), use spread para copiá-lo também.

Mostrar solução
function clonarSuperficial(obj) {
  return { ...obj }; // cópia rasa: apenas o primeiro nível
}

function clonarProfundo(obj) {
  const novo = { ...obj }; // copia o primeiro nível
  for (const chave in novo) {
    const valor = novo[chave];
    if (valor !== null && typeof valor === 'object' && !Array.isArray(valor)) {
      novo[chave] = { ...valor }; // copia o objeto aninhado (um nível)
    }
  }
  return novo;
}

// Teste
const original = { a: 1, b: { c: 2 } };
const copiaRasa = clonarSuperficial(original);
const copiaProfunda = clonarProfundo(original);

copiaRasa.b.c = 99;    // altera o objeto aninhado compartilhado
copiaProfunda.b.c = 100; // altera apenas a cópia profunda

console.log(original.b.c);    // 99
console.log(copiaRasa.b.c);   // 99
console.log(copiaProfunda.b.c); // 100

Passo a passo

  1. clonarSuperficial retorna { ...obj }, que copia as propriedades do primeiro nível. Objetos aninhados continuam sendo a mesma referência.
  2. clonarProfundo começa com uma cópia rasa ({ ...obj }).
  3. O loop for...in percorre todas as chaves enumeráveis do novo objeto.
  4. Para cada chave, verificamos se o valor é um objeto não nulo e não array.
  5. Se for, substituímos por uma nova cópia rasa daquele objeto ({ ...valor }), quebrando a referência compartilhada.
  6. Retornamos o objeto com aninhamentos copiados.
  7. Nos testes, alteramos b.c nas duas cópias e observamos que a original só é afetada pela cópia rasa.

Por que funciona

A cópia rasa copia apenas as referências dos objetos internos. A cópia profunda (um nível) cria novos objetos para cada propriedade que seja um objeto, então alterações nesses objetos não afetam o original. Isso demonstra a diferença fundamental entre shallow e deep copy.

Erros comuns

  • Confundir typeof null: typeof null é 'object', por isso a verificação valor !== null é obrigatória.
  • Esquecer de excluir arrays: arrays também são objetos; se não quiser copiá-los como objetos, use !Array.isArray(valor).
  • Achar que spread faz cópia profunda: { ...obj } não copia aninhamentos; é preciso fazer manualmente.

Outra forma de resolver

Usando structuredClone (disponível em ambientes modernos):

const copiaProfunda = structuredClone(original);

É mais simples e lida com arrays, datas, etc., mas não está disponível em todos os ambientes antigos.

Saída esperada

99
99
100