Se eu clonar um array, uso cloneArr = arr.slice()
Eu quero saber como clonar um objeto em nodejs.
Respostas:
Para utilitários e classes onde não há necessidade de espremer cada gota de desempenho, geralmente eu trapaceio e apenas uso JSON para realizar uma cópia profunda:
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
Esta não é a única resposta ou a resposta mais elegante; todas as outras respostas devem ser consideradas para gargalos de produção. No entanto, essa é uma solução rápida e suja, bastante eficaz e útil na maioria das situações em que eu clonaria um simples hash de propriedades.
newObj = obj.clone(args...);
Object.assign não foi mencionado em nenhuma das respostas acima.
let cloned = Object.assign({}, source);
Se você estiver no ES6, pode usar o operador de propagação:
let cloned = { ... source };
Referência: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
let a = {x:1}; let b = Object.assign({}, a); a.x = 2; a.y = 1; console.log(a, b);
Existem alguns módulos Node lá fora, se você não quiser "lançar o seu próprio". Este parece bom: https://www.npmjs.com/package/clone
Parece que ele lida com todos os tipos de coisas, incluindo referências circulares. Na página do github :
clone masters clonando objetos, matrizes, objetos Date e objetos RegEx. Tudo é clonado recursivamente, para que você possa clonar datas em arrays em objetos, por exemplo. [...] Referências circulares? Sim!
É difícil fazer uma operação de clonagem genérica, mas útil, porque o que deve ser clonado recursivamente e o que deve ser apenas copiado depende de como o objeto específico deve funcionar.
Algo que pode ser útil é
function clone(x)
{
if (x === null || x === undefined)
return x;
if (typeof x.clone === "function")
return x.clone();
if (x.constructor == Array)
{
var r = [];
for (var i=0,n=x.length; i<n; i++)
r.push(clone(x[i]));
return r;
}
return x;
}
Neste código, a lógica é
nullou undefinedapenas retornar o mesmo (o caso especial é necessário porque é um erro tentar ver se um clonemétodo está presente)clone método? então use issoEsta função de clone deve permitir a implementação de métodos de clone personalizados facilmente ... por exemplo
function Point(x, y)
{
this.x = x;
this.y = y;
...
}
Point.prototype.clone = function()
{
return new Point(this.x, this.y);
};
function Polygon(points, style)
{
this.points = points;
this.style = style;
...
}
Polygon.prototype.clone = function()
{
return new Polygon(clone(this.points),
this.style);
};
Quando no objeto você sabe que uma operação de clonagem correta para um array específico é apenas uma cópia superficial, você pode chamar em values.slice()vez de clone(values).
Por exemplo, no código acima, estou exigindo explicitamente que a clonagem de um objeto de polígono clonará os pontos, mas compartilhará o mesmo objeto de estilo. Se eu quiser clonar o objeto de estilo também, posso simplesmente passar clone(this.style).
.clonemétodos próprios. Esta é a melhor maneira de lidar com a clonagem de objetos.
if (x.clone)deveria serif (typeof x.clone === 'function')
Não existe um método nativo para clonar objetos. Implementos sublinhados, _.cloneque é um clone raso.
_.clone = function(obj) {
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
Ele o corta ou o estende.
Aqui está _.extend
// extend the obj (first parameter)
_.extend = function(obj) {
// for each other parameter
each(slice.call(arguments, 1), function(source) {
// loop through all properties of the other objects
for (var prop in source) {
// if the property is not undefined then add it to the object.
if (source[prop] !== void 0) obj[prop] = source[prop];
}
});
// return the object (first parameter)
return obj;
};
Extend simplesmente itera por todos os itens e cria um novo objeto com os itens nele.
Você pode lançar sua própria implementação ingênua se quiser
function clone(o) {
var ret = {};
Object.keys(o).forEach(function (val) {
ret[val] = o[val];
});
return ret;
}
Existem boas razões para evitar a clonagem profunda, pois os fechamentos não podem ser clonados.
Eu pessoalmente fiz uma pergunta sobre deep cloning objects beforee a conclusão a que cheguei é que você simplesmente não faz isso.
Minha recomendação é usar underscoree seu _.clonemétodo para clones rasos
Para uma cópia superficial, gosto de usar o padrão de redução (geralmente em um módulo ou algo assim), assim:
var newObject = Object.keys(original).reduce(function (obj, item) {
obj[item] = original[item];
return obj;
},{});
Aqui está um jsperf para algumas das opções: http://jsperf.com/shallow-copying
Pergunta antiga, mas há uma resposta mais elegante do que a que foi sugerida até agora; use os utils._extend integrados:
var extend = require("util")._extend;
var varToCopy = { test: 12345, nested: { val: 6789 } };
var copiedObject = extend({}, varToCopy);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 } }
Observe o uso do primeiro parâmetro com um objeto vazio {} - isso diz a extend que o (s) objeto (s) copiado (s) precisam ser copiados para um novo objeto. Se você usar um objeto existente como o primeiro parâmetro, o segundo (e todos os subsequentes) parâmetros serão copiados para mesclagem profunda sobre a primeira variável de parâmetro.
Usando as variáveis de exemplo acima, você também pode fazer isso:
var anotherMergeVar = { foo: "bar" };
extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }
Utilitário muito útil, especialmente onde estou acostumado a estender em AngularJS e jQuery.
Espero que isso ajude outra pessoa; as sobregravações de referência de objeto são uma miséria e isso sempre resolve o problema!
Dependendo do que você deseja fazer com seu objeto clonado, você pode utilizar o mecanismo de herança prototípico de javascript e obter um objeto clonado através de:
var clonedObject = Object.create(originalObject);
Lembre-se de que este não é um clone completo - para o bem ou para o mal.
Uma coisa boa sobre isso é que você realmente não duplicou o objeto, então a área de cobertura da memória será baixa.
No entanto, algumas coisas difíceis de lembrar sobre este método são que a iteração de propriedades definidas na cadeia de protótipos às vezes funciona um pouco diferente e o fato de que quaisquer alterações no objeto original afetarão o objeto clonado também, a menos que essa propriedade também tenha sido definida em si mesma .
var a = {foo: "bar"}, b = Object.create(a); a.foo = "broken"; console.log(b.foo); // "broken";
b.foo = "working"; console.log(a.foo); // still "broken";É preciso estar ciente de que as alterações no objeto original serão refletidas no "clone" e que as alterações no "clone" não serão refletidas no objeto original - mas não o chamaria de perigoso - tudo depende do que você quer fazer com seu clone
Implementei uma cópia profunda completa. Acredito que seja a melhor escolha para um método de clone genérico, mas não lida com referências cíclicas.
parent = {'prop_chain':3}
obj = Object.create(parent)
obj.a=0; obj.b=1; obj.c=2;
obj2 = copy(obj)
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
console.log(obj2, obj2.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
parent.prop_chain=4
obj2.a = 15
console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 4
console.log(obj2, obj2.prop_chain)
// '{'a':15, 'b':1, 'c':2} 4
Este código copia objetos com seus protótipos, ele também copia funções (pode ser útil para alguém).
function copy(obj) {
// (F.prototype will hold the object prototype chain)
function F() {}
var newObj;
if(typeof obj.clone === 'function')
return obj.clone()
// To copy something that is not an object, just return it:
if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null)
return obj;
if(typeof obj === 'object') {
// Copy the prototype:
newObj = {}
var proto = Object.getPrototypeOf(obj)
Object.setPrototypeOf(newObj, proto)
} else {
// If the object is a function the function evaluate it:
var aux
newObj = eval('aux='+obj.toString())
// And copy the prototype:
newObj.prototype = obj.prototype
}
// Copy the object normal properties with a deep copy:
for(var i in obj) {
if(obj.hasOwnProperty(i)) {
if(typeof obj[i] !== 'object')
newObj[i] = obj[i]
else
newObj[i] = copy(obj[i])
}
}
return newObj;
}
Com esta cópia não consigo encontrar nenhuma diferença entre o original e o copiado exceto se o original utilizou fechos na sua construção, por isso penso que é uma boa implementação.
Espero que ajude
Objetos e matrizes em JavaScript usam chamada por referência, se você atualizar o valor copiado, ele pode refletir no objeto original. Para evitar isso, você pode clonar profundamente o objeto, para evitar que a referência seja passada, usando o comando run do método cloneDeep da biblioteca lodash
npm instalar lodash
const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)