Come posso clonare correttamente un oggetto JavaScript?


3079

Ho un oggetto x. Vorrei copiarlo come oggetto y, in modo che le modifiche ynon vengano modificate x. Mi sono reso conto che la copia di oggetti derivati ​​da oggetti JavaScript incorporati comporterà proprietà extra indesiderate. Questo non è un problema, dal momento che sto copiando uno dei miei oggetti costruiti letteralmente.

Come posso clonare correttamente un oggetto JavaScript?



256
Per JSON, io usomObj=JSON.parse(JSON.stringify(jsonObject));
Lord Loh.

67
Davvero non capisco perché nessuno suggerisce Object.create(o), fa tutto ciò che l'autore chiede?
froginvasion,

44
var x = { deep: { key: 1 } }; var y = Object.create(x); x.deep.key = 2; Dopo aver fatto questo, y.deep.keysaranno anche 2, quindi Object.create NON PU BE ESSERE UTILIZZATO per la clonazione ...
Ruben Stolk

17
@ r3wt che non funzionerà ... Si prega di pubblicare solo dopo aver fatto il test di base della soluzione ..
akshay,

Risposte:


1561

Fare questo per qualsiasi oggetto in JavaScript non sarà semplice o diretto. Incontrerai il problema di raccogliere erroneamente attributi dal prototipo dell'oggetto che dovrebbero essere lasciati nel prototipo e non copiati nella nuova istanza. Se, ad esempio, stai aggiungendo un clonemetodo Object.prototype, come mostrano alcune risposte, dovrai saltare esplicitamente quell'attributo. E se ci fossero altri metodi aggiuntivi aggiunti Object.prototypeo altri prototipi intermedi di cui non si è a conoscenza? In tal caso, copierai gli attributi che non dovresti, quindi devi rilevare attributi imprevisti e non locali con il hasOwnPropertymetodo.

Oltre agli attributi non enumerabili, riscontrerai un problema più difficile quando provi a copiare oggetti con proprietà nascoste. Ad esempio, prototypeè una proprietà nascosta di una funzione. Inoltre, il prototipo di un oggetto viene referenziato con l'attributo __proto__, anch'esso nascosto, e non verrà copiato da un ciclo for / in che scorre sugli attributi dell'oggetto sorgente. Penso che __proto__potrebbe essere specifico dell'interprete JavaScript di Firefox e potrebbe essere qualcosa di diverso in 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.

Ancora un altro problema nella ricerca di una soluzione elegante è il problema di impostare correttamente l'eredità del prototipo. Se il prototipo del tuo oggetto sorgente è Object, allora semplicemente la creazione di un nuovo oggetto generale {}funzionerà, ma se il prototipo del sorgente è un discendente di Object, allora ti mancheranno i membri aggiuntivi di quel prototipo che hai saltato usando il hasOwnPropertyfiltro, o che erano nel prototipo, ma non erano enumerabili in primo luogo. Una soluzione potrebbe essere quella di chiamare la constructorproprietà dell'oggetto di origine per ottenere l'oggetto di copia iniziale e quindi copiare gli attributi, ma non si otterranno comunque attributi non enumerabili. Ad esempio, un Dateoggetto 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 d1sarà 5 secondi indietro rispetto a quella di d2. Un modo per rendere uno Dateuguale all'altro è quello di chiamare il setTimemetodo, ma che è specifico per la Dateclasse. Non penso che ci sia una soluzione generale a prova di proiettile a questo problema, anche se sarei felice di sbagliarmi!

Quando ho dovuto implementare profondo generale la copia ho finito per compromettere assumendo che avrei solo bisogno di copiare una pianura Object, Array, Date, String, Number, o Boolean. Gli ultimi 3 tipi sono immutabili, quindi potrei eseguire una copia superficiale e non preoccuparmi che cambi. Supponevo inoltre che tutti gli elementi contenuti in Objecto Arraysarebbero stati anche uno dei 6 tipi semplici in quell'elenco. 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à adeguatamente per i 6 tipi semplici che ho citato, purché i dati negli oggetti e nelle matrici formino una struttura ad albero. Cioè, non c'è più di un riferimento agli stessi dati nell'oggetto. 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 oggetto JavaScript, ma potrebbe essere sufficiente per molti scopi, purché non si presuma che funzioni solo per qualsiasi cosa gli si passi.


5
quasi funzionava bene in un nodejs - dovevo solo cambiare la riga per (var i = 0, var len = obj.length; i <len; ++ i) {in for (var i = 0; i <obj.length; ++ i) {
Trindaz,

5
Per i futuri googler: stessa copia approfondita, passando riferimenti in modo ricorsivo invece di utilizzare le dichiarazioni "return" su gist.github.com/2234277
Trindaz

8
Oggi JSON.parse(JSON.stringify([some object]),[some revirer function])sarebbe una soluzione?
KooiInc,

5
Nel primo frammento, sei sicuro che non dovrebbe essere var cpy = new obj.constructor()?
cyon

8
L'assegnazione degli oggetti non sembra fare una vera copia in Chrome, mantiene il riferimento all'oggetto originale - ha finito per usare JSON.stringify e JSON.parse per clonare - ha funzionato perfettamente
1owk3y

974

Se non si usano Dates, funzioni, indefinite, regExp o Infinity all'interno del proprio oggetto, una riga molto semplice è JSON.parse(JSON.stringify(object)):

const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
}
console.log(a);
console.log(typeof a.date);  // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date);  // result of .toISOString()

Funziona con tutti i tipi di oggetti contenenti oggetti, matrici, stringhe, valori booleani e numeri.

Vedi anche questo articolo sull'algoritmo di clone strutturato dei browser che viene utilizzato per pubblicare messaggi da e verso un lavoratore. Contiene anche una funzione per la clonazione profonda.


42
Si noti che può essere utilizzato solo per i test. Innanzitutto, è tutt'altro che ottimale in termini di tempo e consumo di memoria. In secondo luogo, non tutti i browser hanno questo metodo.
Nux,

2
Puoi sempre includere JSON2.js o JSON3.js. Ne avresti bisogno per la tua app comunque. Ma sono d'accordo che questa potrebbe non essere la soluzione migliore, dal momento che JSON.stringify non include le proprietà ereditate.
Tim Hong

78
@Nux, perché non ottimale in termini di tempo e memoria? MiJyn dice: "Il motivo per cui questo metodo è più lento della copia superficiale (su un oggetto profondo) è che questo metodo, per definizione, copie profonde. Ma poiché JSON è implementato nel codice nativo (nella maggior parte dei browser), questo sarà notevolmente più veloce rispetto a qualsiasi altra soluzione di copia profonda basata su javascript e talvolta può essere più veloce di una tecnica di copia superficiale basata su javascript (vedere: jsperf.com/cloning-an-object/79). " stackoverflow.com/questions/122102/...
BeauCielBleu

16
Voglio solo aggiungere un aggiornamento a questo per ottobre 2014. Chrome 37+ è più veloce con JSON.parse (JSON.stringify (oldObject)); Il vantaggio di usare questo è che è molto facile per un motore javascript vedere e ottimizzare qualcosa di meglio se lo desidera.
mirhagk,

17
Aggiornamento 2016: ora dovrebbe funzionare praticamente in tutti i browser ampiamente utilizzati. (vedi Posso usare ... ) La domanda principale ora sarebbe se è sufficientemente performante.
James Foster,

783

Con jQuery, puoi copiare superficialmente con ext :

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

le successive modifiche a copiedObjectnon influiranno su originalObject, e viceversa.

O per fare una copia profonda :

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

164
o anche:var copiedObject = jQuery.extend({},originalObject);
Grant McLean

82
Utile anche per specificare true come primo parametro per la copia profonda:jQuery.extend(true, {}, originalObject);
Will Shaver,

6
Sì, ho trovato utile questo link (stessa soluzione di Pascal) stackoverflow.com/questions/122102/…
Garry English

3
Solo una nota, questo non copia il costruttore di proto dell'oggetto originale
Sam Jones,

1
Secondo stackoverflow.com/questions/184710/… , sembra che "copia superficiale" copi semplicemente il riferimento di originalObject, quindi perché qui lo dice ...subsequent changes to the copiedObject will not affect the originalObject, and vice versa.... Mi dispiace che ero davvero confuso.
Carr

687

In ECMAScript 6 c'è il metodo Object.assign , che copia i valori di tutte le proprietà proprie enumerabili da un oggetto a un altro. Per esempio:

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

Tuttavia, tenere presente che gli oggetti nidificati vengono comunque copiati come riferimento.


Sì, credo che Object.assignsia la strada da percorrere. È anche facile riempirlo di fogli

22
Inoltre, tieni presente che questo copierà i "metodi" definiti tramite valori letterali oggetto (poiché sono enumerabili) ma non i metodi sfidati tramite il meccanismo "class" (poiché questi non sono enumerabili).
Marco Junius Bruto

16
Penso che dovrebbe essere menzionato che questo non è supportato da IE tranne Edge. Alcune persone lo usano ancora.
Saulius,

1
Questo è lo stesso di @EugeneTiurin nella sua risposta.
Appassisci il

5
Parlando per esperienza qui ... NON usare questo. Gli oggetti sono progettati per essere gerarchici e copierai solo il primo livello, portando a assegnare l'intero oggetto che hai copiato. Fidati di me, potrebbe farti risparmiare giorni di graffi alla testa.
ow3n,

233

Per MDN :

  • Se si desidera una copia superficiale, utilizzare Object.assign({}, a)
  • Per una copia "profonda", utilizzare JSON.parse(JSON.stringify(a))

Non sono necessarie librerie esterne ma è necessario verificare prima la compatibilità del browser .


8
JSON.parse (JSON.stringify (a)) sembra bello, ma prima di usarlo ti consiglio di confrontare il tempo necessario per la tua collezione desiderata. A seconda della dimensione dell'oggetto, questa potrebbe non essere l'opzione più rapida.
Edza,

3
Ho notato che il metodo JSON converte gli oggetti data in stringhe ma non in date. Devi avere a che fare con il divertimento dei fusi orari in Javascript e fissare manualmente eventuali date. Possono essere casi simili per altri tipi oltre alle date
Steve Seeger,

per la data, userei moment.js poiché ha clonefunzionalità. vedi di più qui momentjs.com/docs/#/parsing/moment-clone
Tareq

Questo va bene, ma fai attenzione se l'oggetto ha delle funzioni all'interno
lesolorzanov

Un altro problema con l'analisi json sono i riferimenti circolari. Se ci sono riferimenti circolari all'interno dell'oggetto, questo si spezzerà
philoj

133

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

Pertanto, 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. Laddove l'oggetto di origine non verrà modificato, rendendo così la relazione tra i 2 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 nessun loop, nessuna ricorsione. Tuttavia, i browser più vecchi avranno bisogno di un polyfill.


Nota: Object.create non è una copia profonda (itpastorn non ha menzionato alcuna ricorsione). Prova:var a = {b:'hello',c:{d:'world'}}, b = Object.create(a); a == b /* false */; a.c == b.c /* true */;
zamnuts,

103
Questa è eredità prototipale, non clonazione. Queste sono cose completamente diverse. Il nuovo oggetto non ha nessuna delle sue proprietà, punta solo alle proprietà del prototipo. Il punto della clonazione è creare un nuovo oggetto nuovo che non faccia riferimento a nessuna proprietà in un altro oggetto.
d13

7
Sono completamente d'accordo con te. Sono anche d'accordo sul fatto che questa non è la clonazione come potrebbe essere "intesa". Ma forza gente, abbraccia la natura di JavaScript invece di cercare soluzioni oscure che non sono standardizzate. Certo, non ti piacciono i prototipi e sono tutti "blah" per te, ma in realtà sono molto utili se sai cosa stai facendo.
froginvasion,

4
@RobG: questo articolo spiega la differenza tra riferimento e clonazione: en.wikipedia.org/wiki/Cloning_(programmazione) . Object.createpunta alle proprietà del genitore tramite riferimenti. Ciò significa che se i valori delle proprietà del genitore cambiano, anche il figlio cambierà. Ciò ha alcuni effetti collaterali sorprendenti con matrici e oggetti nidificati che potrebbero portare a bug difficili da trovare nel codice se non ne sei a conoscenza: jsbin.com/EKivInO/2 . Un oggetto clonato è un oggetto completamente nuovo e indipendente che ha le stesse proprietà e valori del genitore, ma non è collegato al genitore.
d13,

1
Questo induce in errore le persone ... Object.create () può essere usato come mezzo per l'ereditarietà, ma la clonazione non è in nessun posto vicino ad essa.
prajnavantha,

128

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

Un Object.assignmetodo 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à proprie enumerabili da uno o più oggetti di origine in un oggetto 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;
    }
  });
}

Ci scusiamo per la domanda stupida, ma perché Object.assignprendere due parametri quando la valuefunzione nel polyfill accetta solo un parametro?
Qwertie,

@Qwertie ieri Tutti gli argomenti sono ripetuti e uniti in un oggetto,
dando

Oh capisco, grazie (non avevo familiarità con l' argumentsoggetto prima.) Ho problemi a trovare Object()tramite Google ... è un typecast, no?
Qwertie,

44
questo eseguirà solo una "clonazione" superficiale
Marcus Junius Brutus il

1
Questa risposta è esattamente la stessa di questa: stackoverflow.com/questions/122102/… So che è della stessa persona ma dovresti fare riferimento invece di copiare semplicemente la risposta.
lesolorzanov,

87

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

situazione iniziale

Voglio copiare in profondità un Javascript Objectcon tutti i suoi figli, i loro figli e così via. Ma dal momento che io non sono tipo di uno sviluppatore normale, il mio Objectha normale properties , circular structurese anche nested objects.

Quindi creiamo un circular structuree un nested objectprimo.

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

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

Riuniamo tutto in un Objectnome a.

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

Successivamente, vogliamo copiare ain una variabile denominata be mutarla.

var b = a;

b.x = 'b';
b.nested.y = 'b';

Sai cosa è successo qui perché altrimenti non ti atterresti 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 ) );

b.x = 'b';
b.nested.y = 'b';

Non perdere troppo tempo, otterrai 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'oggetto e gestisce anche altri tipi Date, ma non era un requisito.

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';

Ricorsione e circular structuresnon funziona bene insieme ...RangeError: Maximum call stack size exceeded

soluzione nativa

Dopo aver litigato con il mio collega, il mio capo ci ha chiesto cosa fosse successo e ha trovato una soluzione semplice dopo aver cercato su Google. Si chiama Object.create.

var b = Object.create(a);

b.x = '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 ha funzionato con la struttura nidificata all'interno.

polyfill per la soluzione nativa

Nel Object.createbrowser più vecchio c'è un polyfill proprio come IE 8. È qualcosa come 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);

b.x = 'b';
b.nested.y = 'b';

Ho messo Fal di fuori del campo di applicazione in modo che possiamo dare un'occhiata a ciò che instanceofci 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

Stesso problema della soluzione nativa , ma output leggermente peggiore.

la soluzione migliore (ma non perfetta)

Quando ho cercato, ho trovato una domanda simile ( in Javascript, quando eseguo una copia profonda, come posso evitare un ciclo, a causa di una proprietà "questo"? ) A questo, 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<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; // reset
    } else {
        delete o[gdcc]; // unset again
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

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 il cambiamento instancedi nestede circa 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'oggetto. Gestisce semplice properties, circular structurese nested object, ma sarà rovinare l'istanza di loro, mentre la clonazione.

jsfiddle


12
quindi la congregazione è per evitare quel problema :)
mikus,

@mikus fino a quando non ci sarà una vera specifica che copre più dei semplici casi d'uso, sì.
Fabio Poloni,

2
Un'analisi corretta delle soluzioni fornite sopra, ma le conclusioni tratte dall'autore indicano che non esiste una soluzione a questa domanda.
Amir Mog

2
È un peccato che JS non includa la funzione clone nativa.
lkk

1
Tra tutte le risposte migliori, sento che questo è vicino a quello corretto.
KTU,

77

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

y = _.clone(x);

o puoi estenderlo come

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

2
Grazie. Utilizzando questa tecnica su un server Meteor.
Turbo

Per iniziare rapidamente con lodash, consiglierei di imparare npm, Browserify e lodash. Ho clonato per lavorare con 'npm i --save lodash.clone' e poi 'var clone = require (' lodash.clone ');' Per avere bisogno di lavorare, hai bisogno di qualcosa come browserify. Dopo averlo installato e aver appreso come funziona, utilizzerai "browserify yourfile.js> bundle.js; avvia chrome index.html" ogni volta che esegui il codice (anziché accedere direttamente a Chrome). Questo raccoglie il tuo file e tutti i file richiesti dal modulo npm in bundle.js. Probabilmente puoi risparmiare tempo e automatizzare questo passaggio con Gulp.
Aaron Bell,

65

OK, immagina di avere questo oggetto 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 dipende principalmente da quale ECMAscript stai usando, in ES6+cui puoi semplicemente usare Object.assignper fare il clone:

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

o usando l'operatore di diffusione in questo modo:

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

Ma se stai usando ES5, puoi usare pochi metodi, ma JSON.stringifyassicurati solo di non usarlo per un grosso pezzo di dati da copiare, ma in molti casi potrebbe essere una riga a portata di mano, 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

Potete per favore dare un esempio di cosa big chunk of datasignificherebbe? 100kb? 100MB? Grazie!
user1063287

Sì, @ user1063287, che sostanzialmente i dati più grandi, le prestazioni peggiori ... quindi dipende davvero, non un kb, mb o gb, si tratta più di quante volte vuoi farlo anche ... Inoltre non funzionerà per funzioni e altre cose ...
Alireza

3
Object.assignfa una copia superficiale (proprio come lo spread, @Alizera)
Bogdan D

Non puoi usare let in es5: ^) @Alireza
SensationSama

40

Una soluzione particolarmente inelegante è utilizzare la codifica JSON per eseguire copie profonde di oggetti che non dispongono di metodi membro. La metodologia è quella di codificare JSON l'oggetto target, quindi decodificandolo, ottieni la copia che stai cercando. Puoi decodificare tutte le volte che vuoi fare tutte le copie di cui hai bisogno.

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

Questa metodologia è stata perfetta per il mio caso d'uso, poiché sto archiviando BLOB JSON in un archivio di valori-chiave e quando sono esposti come oggetti in un'API JavaScript, ogni oggetto contiene effettivamente una copia dello stato originale dell'oggetto può calcolare il delta dopo che il chiamante ha mutato l'oggetto 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

Perché le funzioni non appartengono a JSON? Li ho visti trasferiti come JSON più di una volta ...
the_drow,

5
Le funzioni non fanno parte delle specifiche JSON perché non sono un modo sicuro (o intelligente) per trasferire i dati, motivo per cui è stato creato JSON. So che il codificatore JSON nativo in Firefox ignora semplicemente le funzioni passate ad esso, ma non sono sicuro del comportamento degli altri.
Kris Walker,

1
@mark: { 'foo': function() { return 1; } }è un oggetto costruito letteralmente.
Abarnert

Le funzioni di @abarnert non sono dati. "Letterali di funzioni" è un termine improprio - poiché le funzioni possono contenere codice arbitrario, inclusi incarichi e ogni sorta di cose "non serializzabili".
Vemv,

35

Puoi semplicemente usare una proprietà spread per copiare un oggetto senza riferimenti. Ma fai attenzione (vedi commenti), la 'copia' è solo al livello oggetto / array più basso. Le proprietà nidificate sono ancora riferimenti!


Clone completo:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

Clona con riferimenti al secondo livello:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

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

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


1
Questo non funziona ... funzionerebbe probabilmente quando x sarà un array per esempio x = ['ab', 'cd', ...]
Kamil Kiełczewski

3
Funziona, ma tieni presente che questa è una copia SHALLOW, quindi qualsiasi riferimento profondo ad altri oggetti rimane riferimento!
Bugs Bunny,

Un clone parziale può anche accadere in questo modo:const first = {a: 'foo', b: 'bar'}; const second = {...{a} = first}
Cristian Traìna,

25

Per coloro che usano AngularJS, esiste anche un metodo diretto per clonare o estendere gli oggetti in questa libreria.

var destination = angular.copy(source);

o

angular.copy(source, destination);

Altro nella documentazione angular.copy ...


2
Questa è una copia profonda FYI.
Zamnuts,

22

Ecco una funzione che puoi usare.

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;
}

10
Questa risposta è abbastanza vicina, ma non del tutto corretta. Se si tenta di clonare un oggetto Date, non si otterrà la stessa data poiché la chiamata alla funzione di costruzione Date inizializza la nuova Data con la data / ora correnti. Tale valore non è enumerabile e non verrà copiato dal ciclo for / in.
A. Levy,

Non perfetto, ma carino per quei casi di base. Ad esempio, consentire la semplice clonazione di un argomento che può essere un oggetto, una matrice o una stringa di base.
james_womack,

Eseguito l'upgrade per aver chiamato correttamente il costruttore utilizzando new. La risposta accettata no.
GetFree

funziona su nodo tutto il resto! ancora lasciato i link di riferimento
user956584

Il pensiero ricorsivo è eccezionale, ma se il valore è array, funzionerà?
Q10 Visitare il

22

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

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

Se l'oggetto è un elemento DOM XML, dobbiamo usare invece cloneNode

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

Ispirato dallo studio esaustivo 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.


3
Date.prototype.clone = function() {return new Date(+this)};
RobG

22

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;
};

4
Questo è vicino, ma non funziona per nessun oggetto. Prova a clonare un oggetto Date con questo. Non tutte le proprietà sono enumerabili, quindi non verranno visualizzate tutte nel ciclo for / in.
A. Levy,

L'aggiunta all'oggetto prototipo come questo ha rotto jQuery per me. Anche quando ho rinominato clone2.
iPadDeveloper2011

3
@ iPadDeveloper2011 Il codice precedente conteneva un bug in cui creava una variabile globale chiamata 'i' '(per i in questo)', piuttosto che '(per var in questo)'. Ho abbastanza karma per modificarlo e risolverlo e così ho fatto.
mikemaccana,

1
@Calvin: dovrebbe essere creata una proprietà non enumerabile, altrimenti 'clone' apparirà nei cicli 'for'.
mikemaccana,

2
perché non è anche var copiedObj = Object.create(obj);un ottimo modo?
Dan P.

19

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/


12
Non clona in profondità l'oggetto.
Agosto

Questo è un compito, non una copia. clone.Title = "solo un clone" significa che obj.Title = "solo un clone".
HoldOffHunger

@HoldOffHunger Ti sbagli. Controllalo nella console JS del tuo browser ( let obj = {person: 'Thor Odinson'}; let clone = Object.assign({}, obj); clone.title = "Whazzup";)
collapsar

@collapsar: Questo è esattamente ciò che ho controllato, quindi console.log (persona) sarà "Whazzup", non "Thor Odinson". Vedi il commento di agosto.
HoldOffHunger

1
@HoldOffHunger Non accade in Chrome 60.0.3112.113 né in Edge 14.14393; Il commento di August non si applica in quanto i valori dei tipi primitivi delle objproprietà sono effettivamente clonati. I valori delle proprietà che sono oggetti stessi non verranno clonati.
collapsar

18

In ECMAScript 2018

let objClone = { ...obj };

Tenere presente che gli oggetti nidificati vengono comunque copiati come riferimento.


1
Grazie per il suggerimento che gli oggetti nidificati vengono ancora copiati come riferimento! Sono quasi impazzito durante il debug del mio codice perché ho modificato le proprietà nidificate sul "clone" ma l'originale è stato modificato.
Benny Neugebauer,

Questo è ES2016, non il 2018, e questa risposta è stata data due anni prima .
Dan Dascalescu,

e se volessi copiare anche la proprietà nidificata
Sunil Garg

1
@SunilGarg Per copiare anche la proprietà nidificata puoi usare const objDeepClone = JSON.parse(JSON.stringify(obj));
Pavan Garre il

16

Utilizzando Lodash:

var y = _.clone(x, true);

5
OMG sarebbe folle reinventare la clonazione. Questa è l'unica risposta sana.
Dan Ross,

5
Preferisco _.cloneDeep(x)perché essenzialmente è la stessa cosa di cui sopra, ma legge meglio.
Garbanzio,


13

Puoi clonare un oggetto e rimuovere qualsiasi riferimento da quello precedente usando una singola riga di codice. Fai semplicemente:

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'}

Per browser / motori che attualmente non supportano Object.create è possibile utilizzare questo 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();
    };
}

1
+1 Object.create(...)sembra sicuramente la strada da percorrere.
René Nyffenegger,

Risposta perfetta Forse potresti aggiungere una spiegazione per Object.hasOwnProperty? In questo modo le persone sanno come impedire la ricerca del collegamento prototipo.
froginvasion

Funziona bene ma in quali browser funziona il polyfill?
Ian Lunn,

11
Questo sta creando obj2 con un obj1 come prototipo. Funziona solo perché stai ombreggiando il textmembro in obj2. Non stai effettuando una copia, stai solo rimandando alla catena di prototipi quando un membro non viene trovato su obj2.
Nick Desaulniers,

2
Questo NON lo crea "senza riferimenti", sposta semplicemente il riferimento al prototipo. È ancora un riferimento. Se una proprietà cambia nell'originale, lo sarà anche la proprietà prototipo nel "clone". Non è affatto un clone.
Jimbo Jonny,

13

Nuova risposta a una vecchia domanda! Se hai il piacere di usare ECMAScript 2016 (ES6) con Spread Syntax , è facile.

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

Ciò fornisce un metodo pulito per una copia superficiale di un oggetto. Fare una copia profonda, che significa creare una nuova copia di ogni valore in ogni oggetto annidato in modo ricorsivo, richiede le soluzioni più pesanti sopra.

JavaScript continua a evolversi.


2
non funziona quando si hanno funzioni definite sugli oggetti
Petr Marek,

per quanto vedo l'operatore di spread funziona solo con iterables - developer.mozilla.org dice: var obj = {'key1': 'value1'}; var array = [...obj]; // TypeError: obj is not iterable
Oleh

@Oleh quindi usa `{... obj} invece di [... obj];`
manikant gautam

@manikantgautam Prima utilizzavo Object.assign (), ma ora la sintassi di diffusione degli oggetti è supportata negli ultimi Chrome, Firefox (non ancora in Edge e Safari). La sua proposta ECMAScript ... ma Babel lo supporta per quanto posso vedere, quindi probabilmente è sicuro da usare.
Oleh,

12
let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

Soluzione ES6 se si desidera clonare (superficialmente) un'istanza di classe e non solo un oggetto proprietà.


In che modo questo è diverso let cloned = Object.assign({}, obj)?
ceztko,

10

Penso che ci sia una risposta semplice e funzionante. Nella copia profonda ci sono due preoccupazioni:

  1. Mantieni le proprietà indipendenti l'una dall'altra.
  2. E mantieni attivi i metodi sull'oggetto clonato.

Quindi penso che una semplice soluzione sarà prima serializzare e deserializzare e poi fare un compito su di essa per copiare anche le funzioni.

let deepCloned = JSON.parse(JSON.stringify(source));
let merged = Object.assign({}, source);
Object.assign(merged, deepCloned);

Sebbene questa domanda abbia molte risposte, spero che anche questa aiuti.


Anche se mi è permesso importare lodash, preferisco usare lodash cloneDeep.
Condotto

2
Sto usando JSON.parse (JSON.stringify (fonte)). Sempre funzionante.
Misha,

2
@Misha, in questo modo ti mancheranno le funzioni. Il termine "opere" ha molti significati.
Condotto dal

E tieni presente che, come ho già detto, verranno copiate solo le funzioni del primo livello. Quindi, se abbiamo degli oggetti uno dentro l'altro, l'unico modo è copiare ricorsivamente campo per campo.
Condotto dal

9

Per una copia profonda e clone, JSON.stringify quindi JSON.parse l'oggetto:

obj = { a: 0 , b: { c: 0}};
let deepClone = JSON.parse(JSON.stringify(obj));
obj.a = 5;
obj.b.c = 5;
console.log(JSON.stringify(deepClone)); // { a: 0, b: { c: 0}}

abbastanza intelligente ... qualche aspetto negativo di questo approccio?
Aleks,

8

Questo è un adattamento del codice di A. Levy per gestire anche la clonazione di funzioni e riferimenti multipli / ciclici - ciò significa che se due proprietà dell'albero che è clonato sono riferimenti dello stesso oggetto, l'albero degli oggetti clonati avrà questi le proprietà puntano allo stesso clone dell'oggetto referenziato. Questo risolve anche il caso delle dipendenze cicliche che, se lasciate non gestite, portano a un ciclo infinito. La complessità dell'algoritmo è 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;
}

Alcuni test rapidi

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));

1
A partire da settembre 2016, questa è l' unica soluzione corretta alla domanda.
DomQ,

6

Volevo solo aggiungere a tutti Object.create soluzioni in questo post, che questo non funziona nel modo desiderato con nodejs.

In Firefox il risultato di

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

è

{test:"test"}.

In nodejs lo è

{}

Questa è eredità prototipale, non clonazione.
d13

1
@ d13 mentre l'argomento è valido, notare che non esiste un modo standardizzato in JavaScript per clonare un oggetto. Questa è un'eredità prototipica, ma può essere usata come cloni se capisci i concetti.
froginvasion

@froginvasion. L'unico problema con l'utilizzo di Object.create è che gli oggetti e gli array nidificati sono solo riferimenti a puntatori agli oggetti e agli array nidificati del prototipo. jsbin.com/EKivInO/2/edit?js,console . Tecnicamente un oggetto "clonato" dovrebbe avere le sue proprietà uniche che non sono riferimenti condivisi alle proprietà su altri oggetti.
d13,

@ d13 ok, ora vedo il tuo punto. Ma quello che volevo dire è che troppe persone sono alienate dal concetto di eredità prototipica e per me non riesco a capire come funziona. Se non sbaglio, il tuo esempio può essere risolto semplicemente chiamando Object.hasOwnPropertyper verificare se possiedi l'array o meno. Sì, questo aggiunge ulteriore complessità per gestire l'eredità prototipica.
froginvasion,

6
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;
};

2
if(!src && typeof src != "object"){. Penso che dovrebbe essere ||non &&.
MikeM,

6

Poiché mindeavor ha affermato che l'oggetto da clonare è un oggetto "costruito letteralmente", una soluzione potrebbe essere semplicemente quella di generare l'oggetto più volte anziché clonare un'istanza dell'oggetto:

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

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();

6

Ho scritto la mia implementazione. Non sono sicuro se conta come una soluzione migliore:

/*
    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)    /
*/

Di seguito è l'implementazione:

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;
}

non funziona per il mio oggetto, sebbene il mio caso sia un po 'complesso.
Sajuuk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.