Come faccio a clonare correttamente un object JavaScript?

Ho un object, x . Mi piacerebbe copiarlo come object y , tale che le modifiche a y non modificano x . Mi sono reso conto che copiare oggetti derivati ​​da oggetti JavaScript incorporati comporta proprietà extra indesiderate. Questo non è un problema, dal momento che sto copiando uno dei miei oggetti letterali.

Come faccio a clonare correttamente un object JavaScript?

Fare questo per qualsiasi object in JavaScript non sarà semplice o diretto. Ti imbatterai nel problema di raccogliere erroneamente gli attributi dal prototipo dell’object che dovrebbero essere lasciati nel prototipo e non copiati nella nuova istanza. Se, per esempio, si aggiunge un metodo clone a Object.prototype , come mostrano alcune risposte, è necessario saltare esplicitamente tale attributo. Ma cosa succede se ci sono altri metodi aggiuntivi aggiunti a Object.prototype o ad altri prototipi intermedi di cui non si conosce la conoscenza? In tal caso, copi gli attributi che non dovresti, quindi devi rilevare attributi non previsti non locali con il metodo hasOwnProperty .

Oltre agli attributi non enumerabili, si verificherà un problema più difficile quando si tenta di copiare oggetti con proprietà nascoste. Ad esempio, il prototype è una proprietà nascosta di una funzione. Inoltre, il prototipo di un object è referenziato con l’attributo __proto__ , che è anche nascosto, e non verrà copiato da un ciclo for / in iterando sugli attributi dell’object sorgente. Penso che __proto__ potrebbe essere specifico per l’interprete JavaScript di Firefox e potrebbe essere diverso dagli altri browser, ma ottieni l’immagine. Non tutto è enumerabile. Puoi copiare un attributo nascosto se conosci il suo nome, ma non conosco alcun modo per scoprirlo automaticamente.

Un altro ostacolo nella ricerca di una soluzione elegante è il problema di impostare correttamente l’ereditarietà del prototipo. Se il prototipo del tuo object sorgente è Object , allora semplicemente la creazione di un nuovo object generale con {} funzionerà, ma se il prototipo della sorgente è un discendente di Object , allora ti mancheranno i membri aggiuntivi da quel prototipo che hai saltato usando il filtro hasOwnProperty , o che erano nel prototipo, ma non erano enumerabili in primo luogo. Una soluzione potrebbe essere chiamare la proprietà del constructor dell’object di origine per ottenere l’object di copia iniziale e quindi copiare gli attributi, ma in tal caso non si otterranno attributi non enumerabili. Ad esempio, un object Date memorizza i suoi dati come membro nascosto:

 function clone(obj) { if (null == obj || "object" != typeof obj) return obj; var copy = obj.constructor(); for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; } return copy; } var d1 = new Date(); /* Executes function after 5 seconds. */ setTimeout(function(){ var d2 = clone(d1); alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString()); }, 5000); 

La stringa della data per d1 sarà 5 secondi indietro rispetto a quella di d2 . Un modo per rendere una Date uguale a un’altra è chiamare il metodo setTime , ma è specifico per la class Date . Non penso che ci sia una soluzione generale a prova di proiettile per questo problema, anche se sarei felice di sbagliare!

Quando ho dovuto implementare una copia profonda generale, ho finito col compromettere assumendo che avrei solo bisogno di copiare un Object , una Array , una Date , una String , un Number o un Boolean . Gli ultimi 3 tipi sono immutabili, quindi potrei eseguire una copia superficiale e non preoccuparmi che cambi. Assunsi inoltre che qualsiasi elemento contenuto in Object o Array sarebbe anche uno dei 6 tipi semplici in quella lista. Questo può essere realizzato con un codice simile al seguente:

 function clone(obj) { var copy; // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; // Handle Date if (obj instanceof Date) { copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { copy = []; for (var i = 0, len = obj.length; i < len; i++) { copy[i] = clone(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } 

La funzione sopra funzionerà in modo adeguato per i 6 tipi semplici che ho menzionato, purché i dati negli oggetti e nelle matrici formino una struttura ad albero. Cioè, non c'è più di un riferimento agli stessi dati nell'object. Per esempio:

 // This would be cloneable: var tree = { "left" : { "left" : null, "right" : null, "data" : 3 }, "right" : null, "data" : 8 }; // This would kind-of work, but you would get 2 copies of the // inner node instead of 2 references to the same copy var directedAcylicGraph = { "left" : { "left" : null, "right" : null, "data" : 3 }, "data" : 8 }; directedAcyclicGraph["right"] = directedAcyclicGraph["left"]; // Cloning this would cause a stack overflow due to infinite recursion: var cyclicGraph = { "left" : { "left" : null, "right" : null, "data" : 3 }, "data" : 8 }; cyclicGraph["right"] = cyclicGraph; 

Non sarà in grado di gestire alcun object JavaScript, ma potrebbe essere sufficiente per molti scopi, a patto che non si presuma che funzionerà solo per qualsiasi cosa venga lanciata.

Con jQuery, puoi copiare in modo superficiale con estensione :

 var copiedObject = jQuery.extend({}, originalObject) 

le successive modifiche a copyObject non avranno effetto su originalObject e viceversa.

O per fare una copia profonda :

 var copiedObject = jQuery.extend(true, {}, originalObject) 

Se non si utilizzano le funzioni all’interno del proprio object, una fodera molto semplice può essere la seguente:

 var cloneOfA = JSON.parse(JSON.stringify(a)); 

Questo funziona per tutti i tipi di oggetti contenenti oggetti, matrici, stringhe, booleani e numeri.

Vedi anche questo articolo sull’algoritmo clone strutturato dei browser che viene utilizzato quando si inviano messaggi da e verso un lavoratore. Contiene anche una funzione per la clonazione profonda.

In ECMAScript 6 esiste il metodo Object.assign , che copia i valori di tutte le proprietà enumerabili da un object a un altro. Per esempio:

 var x = {myProp: "value"}; var y = Object.assign({}, x); 

Ma tieni presente che gli oggetti nidificati vengono comunque copiati come riferimento.

Ci sono molte risposte, ma nessuna che menziona Object.create da ECMAScript 5, che certamente non ti dà una copia esatta, ma imposta la fonte come prototipo del nuovo object.

Quindi, questa non è una risposta esatta alla domanda, ma è una soluzione a una linea e quindi elegante. E funziona meglio per 2 casi:

  1. Dove tale eredità è utile (duh!)
  2. Dove l’object sorgente non verrà modificato, rendendo così la relazione tra i due oggetti un problema.

Esempio:

 var foo = { a : 1 }; var bar = Object.create(foo); foo.a; // 1 bar.a; // 1 foo.a = 2; bar.a; // 2 - prototype changed bar.a = 3; foo.a; // Still 2, since setting bar.a makes it an "own" property 

Perché considero questa soluzione superiore? È nativo, quindi senza loop, senza ricorsione. Tuttavia, i browser più vecchi avranno bisogno di un polyfill.

Per MDN :

  • Se vuoi una copia superficiale, usa Object.assign({}, a)
  • Per la copia “profonda”, usa JSON.parse(JSON.stringify(a))

Non è necessario per le librerie esterne ma è necessario prima verificare la compatibilità del browser .

Un modo elegante per clonare un object Javascript in una riga di codice

Un metodo Object.assign fa parte dello standard ECMAScript 2015 (ES6) e fa esattamente ciò di cui hai bisogno.

 var clone = Object.assign({}, obj); 

Il metodo Object.assign () viene utilizzato per copiare i valori di tutte le proprietà enumerabili di uno o più oggetti di origine in un object di destinazione.

Leggi di più…

Il polyfill per supportare i browser più vecchi:

 if (!Object.assign) { Object.defineProperty(Object, 'assign', { enumerable: false, configurable: true, writable: true, value: function(target) { 'use strict'; if (target === undefined || target === null) { throw new TypeError('Cannot convert first argument to object'); } var to = Object(target); for (var i = 1; i < arguments.length; i++) { var nextSource = arguments[i]; if (nextSource === undefined || nextSource === null) { continue; } nextSource = Object(nextSource); var keysArray = Object.keys(nextSource); for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex]; var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey); if (desc !== undefined && desc.enumerable) { to[nextKey] = nextSource[nextKey]; } } } return to; } }); } 

Se stai bene con una copia superficiale, la libreria underscore.js ha un metodo clone .

 y = _.clone(x); 

oppure puoi estenderlo come

 copiedObject = _.extend({},originalObject); 

Ci sono diversi problemi con la maggior parte delle soluzioni su Internet. Così ho deciso di fare un follow-up, che include, perché la risposta accettata non dovrebbe essere accettata.

situazione di partenza

Voglio copiare in profondità un Object Javascript con tutti i suoi figli e i loro figli e così via. Ma dal momento che non sono un normale sviluppatore, il mio Object ha properties normali , circular structures e persino nested objects .

Quindi, prima creiamo una circular structure e un nested object .

 function Circ() { this.me = this; } function Nested(y) { this.y = y; } 

Portiamo tutto insieme in un Object chiamato a .

 var a = { x: 'a', circ: new Circ(), nested: new Nested('a') }; 

Successivamente, vogliamo copiare a in una variabile denominata b e mutarla.

 var b = a; bx = 'b'; b.nested.y = 'b'; 

Sai cosa è successo qui perché se no non ti atterri nemmeno su questa grande domanda.

 console.log(a, b); a --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } 

Ora troviamo una soluzione.

JSON

Il primo tentativo che ho provato è stato usare JSON .

 var b = JSON.parse( JSON.stringify( a ) ); bx = 'b'; b.nested.y = 'b'; 

Non sprecare troppo tempo su di esso, riceverai TypeError: Converting circular structure to JSON .

Copia ricorsiva (la “risposta” accettata)

Diamo un’occhiata alla risposta accettata.

 function cloneSO(obj) { // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; // Handle Date if (obj instanceof Date) { var copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { var copy = []; for (var i = 0, len = obj.length; i < len; i++) { copy[i] = cloneSO(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { var copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } 

Sembra buono, eh? È una copia ricorsiva dell'object e gestisce anche altri tipi, come Date , ma non era un requisito.

 var b = cloneSO(a); bx = 'b'; b.nested.y = 'b'; 

La ricorsione e circular structures non funzionano bene insieme ... RangeError: Maximum call stack size exceeded

soluzione nativa

Dopo aver discusso con il mio collega, il mio capo ci ha chiesto cosa è successo, e ha trovato una soluzione semplice dopo alcuni googling. Si chiama Object.create .

 var b = Object.create(a); bx = 'b'; b.nested.y = 'b'; 

Questa soluzione è stata aggiunta a Javascript qualche tempo fa e persino gestisce circular structure .

 console.log(a, b); a --> Object { x: "a", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } 

... e vedi, non funzionava con la struttura annidata all'interno.

polyfill per la soluzione nativa

C'è un polyfill per Object.create nel browser più vecchio proprio come l'IE 8. È simile a quello raccomandato da Mozilla e, naturalmente, non è perfetto e comporta lo stesso problema della soluzione nativa .

 function F() {}; function clonePF(o) { F.prototype = o; return new F(); } var b = clonePF(a); bx = 'b'; b.nested.y = 'b'; 

Ho messo F fuori dal campo di applicazione in modo da poter dare un'occhiata a ciò che instanceof ci dice.

 console.log(a, b); a --> Object { x: "a", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> F { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } console.log(typeof a, typeof b); a --> object b --> object console.log(a instanceof Object, b instanceof Object); a --> true b --> true console.log(a instanceof F, b instanceof F); a --> false b --> true 

Lo stesso problema della soluzione nativa , ma un po 'peggio dell'output.

la migliore (ma non perfetta) soluzione

Quando ho scavato, ho trovato una domanda simile ( in Javascript, quando eseguo una copia profonda, come posso evitare un ciclo, a causa di una proprietà che è "questa"? ) A questa, ma con una soluzione migliore.

 function cloneDR(o) { const gdcc = "__getDeepCircularCopy__"; if (o !== Object(o)) { return o; // primitive value } var set = gdcc in o, cache = o[gdcc], result; if (set && typeof cache == "function") { return cache(); } // else o[gdcc] = function() { return result; }; // overwrite if (o instanceof Array) { result = []; for (var i=0; i 

E diamo un'occhiata all'output ...

 console.log(a, b); a --> Object { x: "a", circ: Object { me: Object { ... } }, nested: Object { y: "a" } } b --> Object { x: "b", circ: Object { me: Object { ... } }, nested: Object { y: "b" } } console.log(typeof a, typeof b); a --> object b --> object console.log(a instanceof Object, b instanceof Object); a --> true b --> true console.log(a instanceof F, b instanceof F); a --> false b --> false 

I requisiti sono abbinati, ma ci sono ancora alcuni problemi minori, tra cui la modifica instance di nested e circ in Object .

La struttura degli alberi che condividono una foglia non verrà copiata, diventeranno due foglie indipendenti:

  [Object] [Object] / \ / \ / \ / \ |/_ _\| |/_ _\| [Object] [Object] ===> [Object] [Object] \ / | | \ / | | _\| |/_ \|/ \|/ [Object] [Object] [Object] 

conclusione

L'ultima soluzione che utilizza la ricorsione e una cache potrebbe non essere la migliore, ma è una vera copia profonda dell'object. Gestisce properties semplici, circular structures e nested object , ma rovinerà l'istanza di essi durante la clonazione.

http://jsfiddle.net/einfallstoll/N4mr2/

Una soluzione particolarmente inelegante è l’uso della codifica JSON per creare copie profonde di oggetti che non hanno metodi membri. La metodologia è quella di codificare JSON dell’object target, quindi decodificandolo si ottiene la copia che si sta cercando. Puoi decodificare tutte le volte che vuoi fare quante copie hai bisogno.

Naturalmente, le funzioni non appartengono a JSON, quindi funziona solo per oggetti senza metodi membro.

Questa metodologia era perfetta per il mio caso d’uso, dal momento che sto memorizzando i BLOB JSON in un archivio di valori-chiave, e quando sono esposti come oggetti in un’API JavaScript, ogni object contiene effettivamente una copia dello stato originale dell’object, quindi può calcolare il delta dopo che il chiamante ha mutato l’object esposto.

 var object1 = {key:"value"}; var object2 = object1; object2 = JSON.stringify(object1); object2 = JSON.parse(object2); object2.key = "a change"; console.log(object1);// returns value 

Per coloro che utilizzano AngularJS, esiste anche un metodo diretto per la clonazione o l’estensione degli oggetti in questa libreria.

 var destination = angular.copy(source); 

o

 angular.copy(source, destination); 

Altro nella documentazione di angular.copy …

Puoi semplicemente usare una proprietà spread per copiare un object senza riferimenti. Ma fai attenzione (vedi commenti), la ‘copia’ è solo sul livello più basso dell’object / array. Le proprietà annidate sono ancora riferimenti!


Clone completo:

 let x = {a: 'value1'} let x2 = {...x} // => mutate without references: x2.a = 'value2' console.log(xa) // => 'value1' 

Clona con riferimenti al secondo livello:

 const y = {a: {b: 'value3'}} const y2 = {...y} // => nested object is still a references: y2.ab = 'value4' console.log(yab) // => 'value4' 

JavaScript in realtà non supporta i cloni profondi in modo nativo. Utilizzare una funzione di utilità. Ad esempio Ramda:

http://ramdajs.com/docs/#clone

OK, immagina di avere questo object qui sotto e vuoi clonarlo:

 let obj = {a:1, b:2, c:3}; //ES6 

o

 var obj = {a:1, b:2, c:3}; //ES5 

La risposta è principalmente depenata su quale ECMAscript stai usando, in ES6+ , puoi semplicemente usare Object.assign per fare il clone:

 let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3}; 

o usando un operatore di spread come questo:

 let cloned = {...obj}; //new {a:1, b:2, c:3}; 

Ma se usi ES5 , puoi usare pochi metodi, ma JSON.stringify , assicurati di non usare per una grande quantità di dati da copiare, ma in molti casi potrebbe essere un modo pratico, qualcosa del genere:

 let cloned = JSON.parse(JSON.stringify(obj)); //new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over 

La risposta di A.Levy è quasi completa, ecco il mio piccolo contributo: c’è un modo per gestire i riferimenti ricorsivi , vedere questa linea

if(this[attr]==this) copy[attr] = copy;

Se l’object è un elemento DOM XML, dobbiamo usare invece cloneNode

if(this.cloneNode) return this.cloneNode(true);

Ispirato dallo studio esauriente di A.Levy e dall’approccio di prototipazione di Calvin, offro questa soluzione:

 Object.prototype.clone = function() { if(this.cloneNode) return this.cloneNode(true); var copy = this instanceof Array ? [] : {}; for(var attr in this) { if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone) copy[attr] = this[attr]; else if(this[attr]==this) copy[attr] = copy; else copy[attr] = this[attr].clone(); } return copy; } Date.prototype.clone = function() { var copy = new Date(); copy.setTime(this.getTime()); return copy; } Number.prototype.clone = Boolean.prototype.clone = String.prototype.clone = function() { return this; } 

Vedi anche la nota di Andy Burke nelle risposte.

Da questo articolo: Come copiare matrici e oggetti in Javascript di Brian Huisman:

 Object.prototype.clone = function() { var newObj = (this instanceof Array) ? [] : {}; for (var i in this) { if (i == 'clone') continue; if (this[i] && typeof this[i] == "object") { newObj[i] = this[i].clone(); } else newObj[i] = this[i] } return newObj; }; 

In ES-6 puoi semplicemente usare Object.assign (…). Ex:

 let obj = {person: 'Thor Odinson'}; let clone = Object.assign({}, obj); 

Un buon riferimento è qui: https://googlechrome.github.io/samples/object-assign-es6/

Here is a function you can use.

 function clone(obj) { if(obj == null || typeof(obj) != 'object') return obj; var temp = new obj.constructor(); for(var key in obj) temp[key] = clone(obj[key]); return temp; } 

You can clone an object and remove any reference from the previous one using a single line of code. Simply do:

 var obj1 = { text: 'moo1' }; var obj2 = Object.create(obj1); // Creates a new clone without references obj2.text = 'moo2'; // Only updates obj2's text property console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'} 

For browsers / engines that do not currently support Object.create you can use this polyfill:

 // Polyfill Object.create if it does not exist if (!Object.create) { Object.create = function (o) { var F = function () {}; F.prototype = o; return new F(); }; } 

New answer to an old question! If you have the pleasure of having using ECMAScript 2016 (ES6) with Spread Syntax , it’s easy.

 keepMeTheSame = {first: "Me!", second: "You!"}; cloned = {...keepMeTheSame} 

This provides a clean method for a shallow copy of an object. Making a deep copy, meaning makign a new copy of every value in every recursively nested object, requires on of the heavier solutions above.

JavaScript keeps evolving.

Using Lodash:

 var y = _.clone(x, true); 
 let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj) 

ES6 solution if you want to (shallow) clone a class instance and not just a property object.

Interested in cloning simple objects :

JSON.parse(JSON.stringify(json_original));

Source : How to copy JavaScript object to new variable NOT by reference?

Jan Turoň’s answer above is very close, and may be the best to use in a browser due to compatibility issues, but it will potentially cause some strange enumeration issues. For instance, executing:

 for ( var i in someArray ) { ... } 

Will assign the clone() method to i after iterating through the elements of the array. Here’s an adaptation that avoids the enumeration and works with node.js:

 Object.defineProperty( Object.prototype, "clone", { value: function() { if ( this.cloneNode ) { return this.cloneNode( true ); } var copy = this instanceof Array ? [] : {}; for( var attr in this ) { if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone ) { copy[ attr ] = this[ attr ]; } else if ( this[ attr ] == this ) { copy[ attr ] = copy; } else { copy[ attr ] = this[ attr ].clone(); } } return copy; } }); Object.defineProperty( Date.prototype, "clone", { value: function() { var copy = new Date(); copy.setTime( this.getTime() ); return copy; } }); Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } ); Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } ); Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } ); 

This avoids making the clone() method enumerable because defineProperty() defaults enumerable to false.

This is an adaptation of A. Levy’s code to also handle the cloning of functions and multiple/cyclic references – what this means is that if two properties in the tree which is cloned are references of the same object, the cloned object tree will have these properties point to one and the same clone of the referenced object. This also solves the case of cyclic dependencies which, if left unhandled, leads to an infinite loop. The complexity of the algorithm is O(n)

 function clone(obj){ var clonedObjectsArray = []; var originalObjectsArray = []; //used to remove the unique ids when finished var next_objid = 0; function objectId(obj) { if (obj == null) return null; if (obj.__obj_id == undefined){ obj.__obj_id = next_objid++; originalObjectsArray[obj.__obj_id] = obj; } return obj.__obj_id; } function cloneRecursive(obj) { if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj; // Handle Date if (obj instanceof Date) { var copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { var copy = []; for (var i = 0; i < obj.length; ++i) { copy[i] = cloneRecursive(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { if (clonedObjectsArray[objectId(obj)] != undefined) return clonedObjectsArray[objectId(obj)]; var copy; if (obj instanceof Function)//Handle Function copy = function(){return obj.apply(this, arguments);}; else copy = {}; clonedObjectsArray[objectId(obj)] = copy; for (var attr in obj) if (attr != "__obj_id" && obj.hasOwnProperty(attr)) copy[attr] = cloneRecursive(obj[attr]); return copy; } throw new Error("Unable to copy obj! Its type isn't supported."); } var cloneObj = cloneRecursive(obj); //remove the unique ids for (var i = 0; i < originalObjectsArray.length; i++) { delete originalObjectsArray[i].__obj_id; }; return cloneObj; } 

Some quick tests

 var auxobj = { prop1 : "prop1 aux val", prop2 : ["prop2 item1", "prop2 item2"] }; var obj = new Object(); obj.prop1 = "prop1_value"; obj.prop2 = [auxobj, auxobj, "some extra val", undefined]; obj.nr = 3465; obj.bool = true; obj.f1 = function (){ this.prop1 = "prop1 val changed by f1"; }; objclone = clone(obj); //some tests i've made console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool)); objclone.f1(); console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1')); objclone.f1.prop = 'some prop'; console.log("test function cloning 2: " + (obj.f1.prop == undefined)); objclone.prop2[0].prop1 = "prop1 aux val NEW"; console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1)); console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1)); 

I’ve written my own implementation. Not sure if it counts as a better solution:

 /* a function for deep cloning objects that contains other nested objects and circular structures. objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object. index (z) | | | | | | depth (x) |_ _ _ _ _ _ _ _ _ _ _ _ /_/_/_/_/_/_/_/_/_/ /_/_/_/_/_/_/_/_/_/ /_/_/_/_/_/_/...../ /................./ /..... / / / /------------------ object length (y) / */ 

Following is the implementation:

 function deepClone(obj) { var depth = -1; var arr = []; return clone(obj, arr, depth); } /** * * @param obj source object * @param arr 3D array to store the references to objects * @param depth depth of the current object relative to the passed 'obj' * @returns {*} */ function clone(obj, arr, depth){ if (typeof obj !== "object") { return obj; } var length = Object.keys(obj).length; // native method to get the number of properties in 'obj' var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object if(result instanceof Array){ result.length = length; } depth++; // depth is increased because we entered an object here arr[depth] = []; // this is the x-axis, each index here is the depth arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props) // start the depth at current and go down, cyclic structures won't form on depths more than the current one for(var x = depth; x >= 0; x--){ // loop only if the array at this depth and length already have elements if(arr[x][length]){ for(var index = 0; index < arr[x][length].length; index++){ if(obj === arr[x][length][index]){ return obj; } } } } arr[depth][length].push(obj); // store the object in the array at the current depth and length for (var prop in obj) { if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth); } return result; } 

I just wanted to add to all the Object.create solutions in this post, that this does not work in the desired way with nodejs.

In Firefox the result of

 var a = {"test":"test"}; var b = Object.create(a); console.log(b);´ 

is

{test:"test"} .

In nodejs it is

 {} 
 function clone(src, deep) { var toString = Object.prototype.toString; if(!src && typeof src != "object"){ //any non-object ( Boolean, String, Number ), null, undefined, NaN return src; } //Honor native/custom clone methods if(src.clone && toString.call(src.clone) == "[object Function]"){ return src.clone(deep); } //DOM Elements if(src.nodeType && toString.call(src.cloneNode) == "[object Function]"){ return src.cloneNode(deep); } //Date if(toString.call(src) == "[object Date]"){ return new Date(src.getTime()); } //RegExp if(toString.call(src) == "[object RegExp]"){ return new RegExp(src); } //Function if(toString.call(src) == "[object Function]"){ //Wrap in another method to make sure == is not true; //Note: Huge performance issue due to closures, comment this :) return (function(){ src.apply(this, arguments); }); } var ret, index; //Array if(toString.call(src) == "[object Array]"){ //[].slice(0) would soft clone ret = src.slice(); if(deep){ index = ret.length; while(index--){ ret[index] = clone(ret[index], true); } } } //Object else { ret = src.constructor ? new src.constructor() : {}; for (var prop in src) { ret[prop] = deep ? clone(src[prop], true) : src[prop]; } } return ret; }; 

Since mindeavor stated that the object to be cloned is a ‘literal-constructed’ object, a solution might be to simply generate the object multiple times rather than cloning an instance of the object:

 function createMyObject() { var myObject = { ... }; return myObject; } var myObjectInstance1 = createMyObject(); var myObjectInstance2 = createMyObject(); 

Consult http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data for the W3C’s “Safe passing of structured data” algorithm, intended to be implemented by browsers for passing data to eg web workers. However, it has some limitations, in that it does not handle functions. See https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm for more information, including an alternative algorithm in JS which gets you part of the way there.

Bellow is my version of deep cloning, covering functions and with handling for circular references.

https://github.com/radsimu/UaicNlpToolkit/blob/master/Modules/GGS/GGSEngine/src/main/resources/ro/uaic/info/nlptools/ggs/engine/core/jsInitCode.js#L17