Clonar profundamente um objeto em JavaScript

Harshit Jindal 12 outubro 2023
  1. Cópia superficial vs cópia profunda
  2. Métodos de cópia superficial em JavaScript
  3. Métodos Deep Copy em JavaScript
Clonar profundamente um objeto em JavaScript

JavaScript é uma linguagem de objetos. Quase tudo é um objeto em JavaScript. Booleanos, Números, Strings, Dates, Maths, Regex, Arrays, função e os próprios objetos, todos são objetos. Eles são uma coleção de pares de valores-chave que consistem em vários atributos e métodos. Eles são armazenados diretamente na memória e podem ser copiados apenas por referência. Uma variável não armazena o objeto, mas apenas uma referência a esse objeto na memória. Então, quando tentamos copiar uma variável de objeto, acabamos criando uma referência extra para o mesmo objeto. Este método é chamado de cópia superficial. Não é ideal, pois não queremos que a mudança no objeto original afete seu clone. Isso cria a necessidade de um método para clonar profundamente o objeto. Este tutorial ensina como clonar profundamente um objeto em JavaScript.

Cópia superficial vs cópia profunda

Uma cópia superficial é uma cópia bit a bit do objeto. O novo objeto criado copia com sucesso os primitivos como números, booleanos e strings, mas não copia nenhuma referência a objetos. Apenas os endereços de referência resultam em um ponteiro apontando para o mesmo objeto. Quaisquer alterações feitas no objeto original são refletidas na cópia superficial.

Por outro lado, uma cópia profunda não copia apenas o endereço/referência para o objeto original, mas todo o objeto. O novo objeto criado não possui nenhuma dependência do objeto copiado. JavaScript fornece vários métodos integrados para copiar um objeto, mas a cópia superficial é o comportamento padrão na maioria deles.

Métodos de cópia superficial em JavaScript

Abordaremos brevemente os métodos de cópia superficial para informá-lo sobre algumas das formas erradas de cópia profunda.

Use a sintaxe de propagação para clonar superficialmente um objeto em JavaScript

Podemos clonar um objeto criando um novo objeto e, em seguida, usando a sintaxe de propagação para enumerar o conteúdo de um objeto dentro dele como se fosse seu. Parece o caminho certo, mas cria uma cópia superficial dos dados.

const obj = {
  a: 1,
  b: {c: 2}
}

const clone = {...obj};  // creates a shallow copy

obj.b.c = 5;
console.log(clone.b.c);  // outputs 5

No código acima, usamos a sintaxe spread para criar uma cópia superficial do objeto. Em seguida, modificamos uma das propriedades do objeto referenciado no objeto original e mostramos que a propriedade é modificada no objeto clonado.

Use o Object.assign() para clonar superficialmente um objeto em JavaScript

O método object.assign() atribui uma cópia superficial do objeto a uma nova variável de objeto. Leva dois argumentos: destino e origem. O alvo é geralmente um par de parênteses vazio usado para representar o objeto vazio no qual copiar; é um argumento opcional, mas transmiti-lo garante que não acabemos alterando o objeto original. O segundo argumento é o objeto a ser copiado.

const obj = {
  a: 1,
  b: {c: 2}
}

const clone = Object.assign({}, obj);  // creates a shallow copy

obj.b.c = 5;
console.log(clone.b.c);  // outputs 5

No código acima, usamos Object.assign() para criar uma cópia superficial do objeto. Em seguida, modificamos uma das propriedades do objeto referenciado no objeto original e mostramos que a propriedade é modificada no objeto clonado.

Métodos Deep Copy em JavaScript

Use JSON.parse() e JSON.stringify() para clonar profundamente um objeto em JavaScript

JSON.stringify() é usado para converter um objeto JavaScript em uma string JSON e JSON.parse() é usado para converter uma string JSON em um objeto JavaScript. Podemos envolver JSON.parse() em torno de JSON.stringify() para primeiro converter o objeto JavaScript em String JSON e, em seguida, analisá-lo para obter uma cópia do objeto.

var user = {name: 'Harshit', age: 21, Profession: 'Software Engineer'};
let fakeDeepCopy = JSON.parse(JSON.stringify(user));

Este método cria uma cópia profunda, mas apenas para objetos sem funções. Ele tem problemas com quaisquer dependências circulares, como outros objetos referenciados. A ordem das propriedades no objeto copiado também pode ser diferente do objeto original. Portanto, este método é um bom truque se tivermos um objeto simples com poucos tipos de dados primitivos, mas não é recomendado para o mundo real.

Use a clonagem profunda nativa para clonar profundamente um objeto em JavaScript

Podemos usar o algoritmo de serialização do módulo Node.js v8 para clonar profundamente um objeto. Embora esteja limitado a determinados tipos de dados integrados, ele preserva as referências nos dados clonados. Ele nos permite copiar várias estruturas cíclicas e recursivas que não eram suportadas pelo método JSON.

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

Nós desserializamos e, em seguida, serializamos o objeto exatamente como stringify e parse dos métodos JSON. Mas ele preserva dependências circulares e é um pouco melhor.

Use a biblioteca Lodash para clonar profundamente um objeto em JavaScript

A biblioteca Lodash tem funções para cópia superficial e profunda, nomeadamente clone e clonedeep. É uma ótima biblioteca que nos permite importar apenas as funções de que precisamos e não a biblioteca completa. O método clonedeep funciona copiando recursivamente o valor e preservando todas as heranças do objeto, criando uma cópia verdadeira do objeto.

const lodashClonedeep = require('lodash.clonedeep');
let obj = {a: 1, b: {c: 2}} let deepClone = lodashClonedeep(obj);

Aqui carregamos a função clonedeep do lodash e a usamos para clonar profundamente o objeto. É uma biblioteca bem testada e mantida, mas só pode ser usada com Node.js e não Vanilla JavaScript.

Use o método jQuery extend() para clonar profundamente um objeto em JavaScript

Podemos usar o .extend() do jQuery para copiar superficialmente e em profundidade um objeto. É o método de clonagem profunda mais confiável, sem perda ou corrupção de dados. Sua principal função é fundir dois ou mais objetos. Mas também pode ser usado para clonar um objeto. Recebe os seguintes argumentos: [deep], target, object1 ..... objectN.

  1. [deep]: É um argumento opcional. Seu único valor permitido é verdadeiro. Se for passado na função, a função criará uma cópia profunda do objeto. Caso contrário, ele forma uma cópia superficial.
  2. target: O objeto a ser estendido. Ele receberá todos os objetos mesclados.
  3. object1, ..., objectN: Estes são os objetos a serem fundidos/clonados em um novo objeto.
let obj = {a: 1, b: {c: 2}} let shallowClone =
    $.extend({}, obj);                    // creates a shallow copy
let deepClone = $.extend(true, {}, obj);  // creates a deep copy

Uma solução mais óbvia pode ser apenas iterar por meio de cada propriedade do objeto de origem e replicá-los em um novo objeto. Todos os métodos discutidos acima são compatíveis com todos os principais navegadores.

Harshit Jindal avatar Harshit Jindal avatar

Harshit Jindal has done his Bachelors in Computer Science Engineering(2021) from DTU. He has always been a problem solver and now turned that into his profession. Currently working at M365 Cloud Security team(Torus) on Cloud Security Services and Datacenter Buildout Automation.

LinkedIn

Artigo relacionado - JavaScript Object