Cópia por Valor e Cópia por Referência no JavaScript

  1. Tipos Primitivos (Cópia por Valor)

Quando se trabalha com valores primitivos em JavaScript, a atribuição realiza uma cópia do valor.

let primeiroValor = 15;
let segundoValor = primeiroValor;  // Cópia por valor
segundoValor = 25;
console.log(primeiroValor);  // 15, o original não se altera
console.log(segundoValor);   // 25

  1. Tipos de Objeto (Cópia por Referência)

Para objetos, arrays e outras estruturas complexas, a atribuição copia a referência ao mesmo objeto na memória.

let configuracao = { tema: 'claro' };
let copiaConfig = configuracao;  // Cópia por referência
copiaConfig.tema = 'escuro';
console.log(configuracao.tema);  // 'escuro', o objeto original é modificado
console.log(configuracao === copiaConfig);  // true, apontam para o mesmo objeto

  1. Exemplos com Desestruturação

Caso 1: Desestruturando uma propriedade primitiva

Ao dseestruturar uma propriedade primitiva, o valor é copiado independentemente.

let pessoa = { nome: 'Carlos', idade: 30 };
let { nome } = pessoa;  // Equivalente a let nome = pessoa.nome;
nome = 'André';
console.log(nome);        // 'André'
console.log(pessoa.nome); // 'Carlos', o objeto original não é afetado
// Pois 'nome' é uma string (tipo primitivo), cópia por valor

Caso 2: Desestruturando uma propriedade objeto

Propriedades que são objetos mantêm a referência após a desestruturação.

let usuario = {
  nome: 'Carlos',
  localizacao: { cidade: 'São Paulo' },
  interesses: ['leitura', 'cinema']
};

let { localizacao } = usuario;  // 'localizacao' é objeto, cópia por referência
localizacao.cidade = 'Rio de Janeiro';
console.log(usuario.localizacao.cidade);  // 'Rio de Janeiro', o original é alterado

let { interesses } = usuario;  // 'interesses' é array (tipo objeto), cópia por referência
interesses.push('esportes');
console.log(usuario.interesses);  // ['leitura', 'cinema', 'esportes'], modificado

Caso 3: Desestruturação aninhada

Em desestruturação aninhada, as referências são preservadas em todos os níveis de objeetos.

let dados = {
  informacao: {
    pessoal: {
      nome: 'Carlos',
      idade: 30
    }
  }
};

let { informacao: { pessoal } } = dados;
pessoal.idade = 35;
console.log(dados.informacao.pessoal.idade);  // 35, o original é modificado
// Pois 'pessoal' é um objeto, mantém a referência

  1. Atribuição Direta versus Desestruturação

A cópia por valor ocorre tanto para atribuição direta de propriedades primitivas quento para desestruturação delas.

// Atribuição direta
let objetoA = { nome: 'Carlos' };
let valorDireto = objetoA.nome;  // Primitivo, cópia por valor
valorDireto = 'André';
console.log(objetoA.nome);  // 'Carlos', sem alteração

// Desestruturação
let { nome: aliasNome } = objetoA;  // Primitivo, cópia por valor
aliasNome = 'Fernando';
console.log(objetoA.nome);  // 'Carlos', sem alteração

// Porém, ao desestruturar uma propriedade objeto
let objetoB = { info: { nome: 'Carlos' } };
let { info: copiaInfo } = objetoB;  // Objeto, cópia por referência
copiaInfo.nome = 'Ricardo';
console.log(objetoB.info.nome);  // 'Ricardo', alterado!

  1. Como Evitar Modificações Acidentais

Método 1: Cópia Profunda

Utilize técnicas de cópia profunda para criar uma instância totalmente nova do objeto.

let original = {
  nome: 'Carlos',
  localizacao: { cidade: 'São Paulo' }
};

// Cópia profunda usando JSON (com limitações para funções, etc.)
let copiaProfunda = JSON.parse(JSON.stringify(original));
// Ou usando a API moderna structuredClone
let copiaModerna = structuredClone(original);

let { localizacao } = copiaModerna;
localizacao.cidade = 'Belo Horizonte';
console.log(original.localizacao.cidade);  // 'São Paulo', original intacto

Método 2: Desestruturação Seletiva

Desestruture apenas os valores primitivos necessários para evitar referências indesejadas.

let endereco = {
  localizacao: {
    cidade: 'São Paulo',
    detalhes: { rua: 'Rua Principal' }
  }
};

// Desestruture apenas as chaves primitivas
let { localizacao: { cidade, detalhes: { rua } } } = endereco;
// Agora 'cidade' e 'rua' são strings (primitivos), cópia por valor
// Modificações nelas não afetam o objeto original

Resumo das Regras

  • Tipos Primitivos (string, number, boolean, null, undefined, symbol, bigint):
    • Atribuição é cópia por valor.
    • Desestruturação também é cópia por valor.
  • Tipos de Objeto (objetos, arrays, funções, Date, etc.):
    • Atribuição é cópia por referência.
    • Na desestruturação, se a propriedade for um tipo objeto, mantém a cópia por referência.
  • Comportamento de Modificação:
    • Para variáveis primitivas, a reatribuição não afeta a fonte.
    • Para variáveis objeto, modificar propriedades do objeto afeta a fonte, mas reatribuir a variável não afeta.
// Exemplo de reatribuição vs modificação de propriedade
let objOriginal = { cor: 'vermelho' };
let objCopia = objOriginal;

objCopia.cor = 'azul';      // Modifica propriedade, objOriginal também muda
console.log(objOriginal.cor); // 'azul'

objCopia = { cor: 'verde' };  // Reatribui a variável, objOriginal não muda
console.log(objOriginal.cor); // 'azul'

Tags: javascript Cópia por Valor Cópia por Referência Desestruturação objetos

Publicado em 6-30 19:11