HOWTO · JavaScript
Clonar profundamente um objeto em JavaScript
Este tutorial apresenta como clonar profundamente um objeto em JavaScript.
Nesta página
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.
[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.target: O objeto a ser estendido. Ele receberá todos os objetos mesclados.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.