Se clono un array, utilizzo cloneArr = arr.slice()
Voglio sapere come clonare un oggetto in nodejs.
Risposte:
Per le utilità e le classi in cui non è necessario spremere ogni goccia di prestazioni, spesso baro e uso solo JSON per eseguire una copia completa:
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
Questa non è l'unica risposta o la risposta più elegante; tutte le altre risposte dovrebbero essere prese in considerazione per i colli di bottiglia della produzione. Tuttavia, questa è una soluzione rapida e sporca, abbastanza efficace e utile nella maggior parte delle situazioni in cui clonerei un semplice hash di proprietà.
newObj = obj.clone(args...);
Object.assign non è stato menzionato in nessuna delle risposte precedenti.
let cloned = Object.assign({}, source);
Se sei su ES6 puoi utilizzare l'operatore spread:
let cloned = { ... source };
Riferimento: 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);
Ci sono alcuni moduli Node là fuori se non vuoi "lanciarne uno tuo". Questo sembra buono: https://www.npmjs.com/package/clone
Sembra che gestisca tutti i tipi di cose, inclusi i riferimenti circolari. Dalla pagina GitHub :
master clone clonando oggetti, array, oggetti Date e oggetti RegEx. Tutto viene clonato in modo ricorsivo, in modo che tu possa clonare le date negli array negli oggetti, per esempio. [...] Riferimenti circolari? Sì!
È difficile eseguire un'operazione di clonazione generica ma utile perché ciò che dovrebbe essere clonato in modo ricorsivo e ciò che dovrebbe essere semplicemente copiato dipende da come dovrebbe funzionare l'oggetto specifico.
Qualcosa che può essere utile è
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;
}
In questo codice la logica è
nullo undefinedsemplicemente restituire lo stesso (il caso speciale è necessario perché è un errore provare a vedere se un clonemetodo è presente)clonemetodo? allora usa quelloQuesta funzione di clonazione dovrebbe consentire l'implementazione di metodi di clonazione personalizzati facilmente ... per esempio
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 nell'oggetto sai che un'operazione di clonazione corretta per un array specifico è solo una copia superficiale, puoi chiamare values.slice()invece di clone(values).
Ad esempio, nel codice precedente, richiedo esplicitamente che la clonazione di un oggetto poligono clonerà i punti, ma condividerà lo stesso oggetto di stile. Se invece voglio clonare anche l'oggetto di stile, posso semplicemente passare clone(this.style).
.clonemetodo da soli. Questo è il modo migliore per gestire la clonazione di oggetti.
if (x.clone)dovrebbe essereif (typeof x.clone === 'function')
Non esiste un metodo nativo per la clonazione di oggetti. Sottolineare gli attrezzi _.cloneche sono un clone superficiale.
_.clone = function(obj) {
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
Lo affetta o lo estende.
Ecco _.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 itera semplicemente attraverso tutti gli elementi e crea un nuovo oggetto con gli elementi al suo interno.
Puoi implementare la tua implementazione ingenua se lo desideri
function clone(o) {
var ret = {};
Object.keys(o).forEach(function (val) {
ret[val] = o[val];
});
return ret;
}
Esistono buone ragioni per evitare la clonazione profonda perché le chiusure non possono essere clonate.
Ho fatto personalmente una domanda deep cloning objects beforee la conclusione a cui sono arrivato è che non lo fai.
La mia raccomandazione è utilizzare underscoreed è un _.clonemetodo per cloni superficiali
Per una copia superficiale, mi piace usare il modello di riduzione (di solito in un modulo o simile), in questo modo:
var newObject = Object.keys(original).reduce(function (obj, item) {
obj[item] = original[item];
return obj;
},{});
Ecco un jsperf per un paio di opzioni: http://jsperf.com/shallow-copying
Vecchia domanda, ma c'è una risposta più elegante di quanto suggerito finora; usa il built-in utils._extend:
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 } }
Notare l'uso del primo parametro con un oggetto vuoto {} - questo dice a Extended che gli oggetti copiati devono essere copiati in un nuovo oggetto. Se utilizzi un oggetto esistente come primo parametro, i secondi (e tutti i successivi) parametri verranno copiati in profondità sulla prima variabile del parametro.
Utilizzando le variabili di esempio sopra, puoi anche fare questo:
var anotherMergeVar = { foo: "bar" };
extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);
console.log(copiedObject);
// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }
Utilità molto utile, soprattutto dove sono abituato a estendere in AngularJS e jQuery.
Spero che questo aiuti qualcun altro; le sovrascritture dei riferimenti agli oggetti sono un problema e questo lo risolve ogni volta!
A seconda di cosa vuoi fare con il tuo oggetto clonato, puoi utilizzare il meccanismo di ereditarietà prototipale di javascript e ottenere un oggetto in qualche modo clonato attraverso:
var clonedObject = Object.create(originalObject);
Ricorda solo che questo non è un clone completo, nel bene e nel male.
Un aspetto positivo è che in realtà non hai duplicato l'oggetto, quindi l'impronta di memoria sarà bassa.
Alcune cose difficili da ricordare riguardo a questo metodo sono che l'iterazione delle proprietà definite nella catena del prototipo a volte funziona in modo leggermente diverso e il fatto che qualsiasi modifica all'oggetto originale influenzerà anche l'oggetto clonato a meno che quella proprietà non sia stata impostata anche su se stessa .
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";Ovviamente bisogna essere consapevoli che i cambiamenti nell'oggetto originale si rifletteranno nel "clone" e che i cambiamenti nel "clone" non si rifletteranno nell'oggetto originale - ma non lo definirei pericoloso - dipende tutto da cosa vuoi fare con il tuo clone
Ho implementato una copia completa completa. Credo che sia la scelta migliore per un metodo di clonazione generico, ma non gestisce i riferimenti ciclici.
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
Questo codice copia gli oggetti con i loro prototipi, copia anche le funzioni (potrebbe essere utile per qualcuno).
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;
}
Con questa copia non riesco a trovare alcuna differenza tra l'originale e quello copiato tranne se l'originale utilizzava chiusure sulla sua costruzione, quindi penso che sia una buona implementazione.
spero possa essere d'aiuto
Gli oggetti e gli array in JavaScript utilizzano la chiamata per riferimento, se aggiorni il valore copiato potrebbe riflettere sull'oggetto originale. Per evitare ciò è possibile clonare in profondità l'oggetto, per impedire il passaggio del riferimento, utilizzando la libreria lodash cloneDeep metodo run command
npm installa lodash
const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)