Wie klonen Sie ein Array von Objekten in Javascript?

419

... wo jedes Objekt auch Verweise auf andere Objekte innerhalb desselben Arrays hat?

Als ich zum ersten Mal auf dieses Problem kam, dachte ich nur an so etwas

var clonedNodesArray = nodesArray.clone()

würde existieren und nach Informationen suchen, wie man Objekte in Javascript klont. Ich habe eine Frage zu StackOverflow gefunden (beantwortet von @JohnResig) und er hat darauf hingewiesen, dass Sie dies mit jQuery tun können

var clonedNodesArray = jQuery.extend({}, nodesArray);

ein Objekt klonen. Ich habe dies versucht, dies kopiert nur die Referenzen der Objekte im Array. Also wenn ich

nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"

Der Wert von NodesArray [0] und ClonedNodesArray [0] wird als "grün" angezeigt. Dann habe ich es versucht

var clonedNodesArray = jQuery.extend(true, {}, nodesArray);

Das Deep kopiert ein Objekt, aber ich habe sowohl von Firebug als auch von Opera Dragonfly die Meldung " Zu viel Rekursion " und " Kontrollstapelüberlauf " erhalten.

Wie würdest du es machen? Ist das etwas, was nicht einmal getan werden sollte? Gibt es eine wiederverwendbare Möglichkeit, dies in Javascript zu tun?

Wallyqs
quelle

Antworten:

105

Das Problem mit Ihrer flachen Kopie ist, dass nicht alle Objekte geklont werden. Während die Verweise auf jedes Objekt in jedem Array eindeutig sind, haben Sie es mit demselben Objekt wie zuvor zu tun, sobald Sie es letztendlich greifen. Es ist nichts Falsches an der Art und Weise, wie Sie es geklont haben ... dasselbe Ergebnis würde mit Array.slice () erzielt.

Der Grund, warum Ihre tiefe Kopie Probleme hat, ist, dass Sie am Ende kreisförmige Objektreferenzen haben. Deep wird so tief wie möglich gehen, und wenn Sie einen Kreis haben, wird es unendlich weitergehen, bis der Browser in Ohnmacht fällt.

Wenn die Datenstruktur nicht als gerichteter azyklischer Graph dargestellt werden kann, bin ich mir nicht sicher, ob Sie eine Allzweckmethode für das Deep Cloning finden werden. Zyklische Graphen bieten viele knifflige Eckfälle, und da dies keine übliche Operation ist, bezweifle ich, dass jemand eine vollständige Lösung geschrieben hat (wenn es überhaupt möglich ist - könnte es nicht sein! Aber ich habe keine Zeit, jetzt zu versuchen, einen strengen Beweis zu schreiben.). Ich habe auf dieser Seite einige gute Kommentare zu diesem Thema gefunden .

Wenn Sie eine ausführliche Kopie eines Array von Objekten mit Zirkelverweisen benötigen, müssen Sie meiner Meinung nach Ihre eigene Methode codieren, um Ihre spezielle Datenstruktur zu verarbeiten, sodass es sich um einen Klon mit mehreren Durchgängen handelt:

  1. Erstellen Sie in Runde 1 einen Klon aller Objekte, die nicht auf andere Objekte im Array verweisen. Behalten Sie die Herkunft jedes Objekts im Auge.
  2. Verbinden Sie in Runde zwei die Objekte miteinander.
Dan Lew
quelle
1
Fixer Link für @PatrickdeKleijn Antwort: web.archive.org/web/20140222022056/http://my.opera.com/…
Mike Szyndel
529

Solange Ihre Objekte JSON-serialisierbaren Inhalt enthalten (keine Funktionen, keine Number.POSITIVE_INFINITYusw.), sind keine Schleifen zum Klonen von Arrays oder Objekten erforderlich. Hier ist eine reine Vanille-Einzeilenlösung.

var clonedArray = JSON.parse(JSON.stringify(nodesArray))

Um die folgenden Kommentare zusammenzufassen, besteht der Hauptvorteil dieses Ansatzes darin, dass auch der Inhalt des Arrays geklont wird, nicht nur das Array selbst. Die Hauptnachteile sind die Beschränkung, nur an JSON-serialisierbaren Inhalten zu arbeiten, und die Leistung (die erheblich schlechter ist als bei aslice basierter Ansatz).

Vladimir Kharlampidi
quelle
116
Dies funktioniert möglicherweise für JSON-Daten. Wenn Ihr Array jedoch Funktionen oder Instanzen von Objekten mit Methoden enthält, verabschieden Sie sich von diesen.
sp0rkyd0rky
10
Seien Sie vorsichtig, wenn Sie ein Array haben, das den Wert Infinity enthält. Dieser Wert geht verloren (ist danach null). ( jsfiddle.net/klickagent/ehm4bd3s )
klickagent.ch
13
Dies ist im Allgemeinen nur ein schlechter Ansatz, es sei denn, Ihr Array enthält nur Grundelemente und / oder Objekte, die selbst nur Zeichenfolgen- / Zahlen- / Boolesche Grundelemente enthalten (auch nullund undefinedwerden Probleme sein, da JSON sie nicht unterstützt). Darüber hinaus ist es ein weitaus weniger effizienter Vorgang als der old_array.slice(0);, der sowohl besser als auch schneller funktionieren sollte.
XML
2
Wenn das Objekt des Arrays DateTime hat, wird anstelle von DateTime eine Zeichenfolge zurückgegeben! neues Datum! == JSON.parse (JSON.stringify (neues Datum))
MarkosyanArtur
2
Die Schlüsselzeile in der Frage des OP, die diese Antwort oben völlig ignoriert: ... wo jedes Objekt auch Verweise auf andere Objekte innerhalb desselben Arrays hat?
XML
287

Ich habe das Klonen eines Arrays von Objekten mit Object.assign gelöst

const newArray = myArray.map(a => Object.assign({}, a));

oder noch kürzer mit Spread-Syntax

const newArray = myArray.map(a => ({...a}));
Dinodsaurus
quelle
13
Wenn myArray jedoch eine Reihe von Dinosauriern enthielt, enthält newArray eine Reihe von Objekten. Das ist lahm, stimmst du nicht zu?
Matthew James Davis
3
Bester Ansatz, da er die Funktionen von Objekten am Leben erhält und sie dann mit JSON.parse (JSON.stringify (nodeArray))
verliert
14
@MatthewJamesDavis können Sie dieses Problem lösen durch Ersetzen {}mit new Dinosaur().
Agargara
5
flache Kopie nicht tiefe Kopie
Sultan Aslam
1
Dies funktioniert gut für eine Reihe von Objekten, wenn diese Objekte nur primitive Eigenschaften enthalten ... was ich brauchte, danke
Mojave
154

Wenn Sie nur eine flache Kopie benötigen, ist dies ganz einfach:

new_array = old_array.slice(0);
Leopd
quelle
6
Ich glaube nicht, dass du 0.slice()
passen
112
Das funktioniert aber nicht wirklich, oder? Ich meine, es ist keine Antwort auf die Frage, wie man ein Array von Objekten klont. Dies ist die Lösung zum Klonen eines einfachen Arrays.
Bozdoz
35
Tatsächlich funktioniert dies für ein Objektarray nicht. Das zurückgegebene Array von sliceist ein neues Array, enthält jedoch die Verweise auf die ursprünglichen Array-Objekte.
Sergio A.
4
Dies funktioniert nur für "generics" int, string usw., nicht jedoch für ein Array von Objekten.
Stefan Michev
5
Für ein Array von Objekten, die nicht geklont werden, wird durch das Aktualisieren auf das neue_Aray auch das alte_Array aktualisiert.
Anas
43

Der beste und aktuellste Weg, diesen Klon zu erstellen, ist wie folgt:

Verwendung der ... ES6-Spread-Operators.

Hier ist das einfachste Beispiel:

var clonedObjArray = [...oldObjArray];

Auf diese Weise verteilen wir das Array in einzelne Werte und fügen es mit dem Operator [] in ein neues Array ein.

Hier ist ein längeres Beispiel, das die verschiedenen Funktionsweisen zeigt:

let objArray = [ {a:1} , {b:2} ];

let refArray = objArray; // this will just point to the objArray
let clonedArray = [...objArray]; // will clone the array

console.log( "before:" );
console.log( "obj array" , objArray );
console.log( "ref array" , refArray );
console.log( "cloned array" , clonedArray );

objArray[0] = {c:3};

console.log( "after:" );
console.log( "obj array" , objArray ); // [ {c:3} , {b:2} ]
console.log( "ref array" , refArray ); // [ {c:3} , {b:2} ]
console.log( "cloned array" , clonedArray ); // [ {a:1} , {b:2} ]

MennyMez
quelle
2
Gute moderne Antwort, die mit älteren Browsern (wie IE 11) nicht funktioniert
Jealie
1
@Jealie Ich vermute, KingpinEX zielt auf diese Antwort für Leute ab, die es6 auf etwas allgemein Nützlicheres mit Babel übertragen, oder was haben Sie.
Ruffin
61
Dadurch wird nur das Array tief kopiert, nicht jedes Objekt im Array.
Toivo Säwén
31
Um zu verfolgen, was @ ToivoSäwén gesagt hat, werden die Objekte im Array nicht tief kopiert. Es verweist weiterhin auf die ursprünglichen Objekte. Wenn Sie sie also mutieren, wirkt sich dies auch auf das ursprüngliche Array aus.
Joel Kinzel
2
Es funktioniert nur für Grundelemente. Versuchen Sie Folgendes: objArray [0] .a = 3; und Sie werden sehen, dass die Referenz des Objekts in clonedArray dieselbe bleibt.
Sergio Correa
25

Das funktioniert bei mir:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend({}, obj);
                  });

Und wenn Sie eine tiefe Kopie der Objekte im Array benötigen:

var clonedArray = $.map(originalArray, function (obj) {
                      return $.extend(true, {}, obj);
                  });
viliks
quelle
1
Das sieht so aus, als würde es funktionieren. Ich versuche, eine umfangreiche Verwendung von jQuery zu vermeiden, daher werde ich es in meiner Situation nicht verwenden, aber eine for-Schleife und for ... in würden funktionieren.
Bozdoz
19
$.evalJSON($.toJSON(origArray));
elsereturn
quelle
2
Sie müssen das jquery json Plugin verwenden, um diesen Code
wmitchell
32
Ohne JQ (gut in modernen Browsern):JSON.parse(JSON.stringify(origArray));
Forresto
Ich fand diesen Kommentar nützlich. In meiner Implementierung musste ich eine Kopie eines Arrays von Objekten erstellen, auf die die beobachtbaren Eigenschaften von KnockoutJS angewendet wurden. Die Kopie benötigte nur die Werte, nicht die Beobachtbarkeit. Um eine Kopie von NUR den Werten zu erstellen, habe ich JSON.parse (ko.toJSON (origArray)) ODER ko.utils.parseJson (ko.toJSON (origArray)) verwendet. Nur meine 2 Cent und danke, dass Sie mir geholfen haben, zu meiner Lösung zu gelangen.
Wavedrop
6
JSON.parse(JSON.stringify(origArray));ist definitiv die einfachste Lösung.
Yorkw
jQuery ist oft nicht notwendig. youmightnotneedjquery.com
ADJenks
9

Map erstellt ein neues Array aus dem alten (ohne Bezug auf das alte). Innerhalb der Map erstellen Sie ein neues Objekt und durchlaufen Eigenschaften (Schlüssel) und weisen dem neuen Objekt Werte aus dem alten Array-Objekt zu, die den entsprechenden Eigenschaften entsprechen.

Dadurch wird genau das gleiche Array von Objekten erstellt.

let newArray = oldArray.map(a => {
               let newObject = {};
               Object.keys(a).forEach(propertyKey => {
                    newObject[propertyKey] = a[propertyKey];
               });
               return newObject ;
});
Eomeroff
quelle
8

Möglicherweise habe ich eine einfache Möglichkeit, dies zu tun, ohne eine schmerzhafte Rekursion durchführen zu müssen und nicht alle feineren Details des betreffenden Objekts zu kennen. Konvertieren Sie mit jQuery einfach Ihr Objekt mithilfe von jQuery in JSON. $.toJSON(myObjectArray)Nehmen Sie dann Ihre JSON-Zeichenfolge und bewerten Sie sie zurück zu einem Objekt. BAM! Gemacht und gemacht! Problem gelöst. :) :)

var oldObjArray = [{ Something: 'blah', Cool: true }];
var newObjArray = eval($.toJSON(oldObjArray));
George
quelle
21
In einigen modernen Browsern ist die JSON-Methode integriert, sodass Sie dies tun können: JSON.parse (JSON.stringify (MY_ARRAY)), die schneller sein sollte. Guter Vorschlag.
Nicolas R
1
Und wenn sie json2 nicht verwenden , nicht eval.
Kamranicus
Dies hat eine schreckliche Leistung, ist aber leider die beste Antwort, die ich gesehen habe: /
Dvid Silva
Bewerten Sie nichts mit Benutzerdaten. eval()Am besten gar nicht verwenden. Es ist ein Sicherheitsrisiko.
ADJenks
8

Ich beantworte diese Frage, weil es keine einfache und explizite Lösung für das Problem des "Klonens eines Arrays von Objekten in Javascript" zu geben scheint:

function deepCopy (arr) {
    var out = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        var item = arr[i];
        var obj = {};
        for (var k in item) {
            obj[k] = item[k];
        }
        out.push(obj);
    }
    return out;
}

// test case

var original = [
    {'a' : 1},
    {'b' : 2}
    ];

var copy = deepCopy(original);

// change value in copy
copy[0]['a'] = 'not 1';

// original[0]['a'] still equals 1

Diese Lösung iteriert die Array-Werte, iteriert dann die Objektschlüssel, speichert diese in einem neuen Objekt und verschiebt dieses neue Objekt in ein neues Array.

Siehe jsfiddle . Hinweis: Ein einfaches .slice()oder [].concat()nicht genug für die Objekte innerhalb des Arrays.

bozdoz
quelle
Vielen Dank für die Antwort, aber Sie hätten die Mängel der Antwort hervorheben sollen. Es funktioniert nicht, wenn die Objekte Objekte enthalten. Richtig?
Harter
Es wird eine flache Kopie erstellt. nicht tief
Sultan Aslam
Sie müssen irgendwo eine Rekursion hinzufügen
DGoiko
6

JQuery Extend funktioniert einwandfrei. Sie müssen lediglich angeben, dass Sie ein Array anstelle eines Objekts klonen ( beachten Sie das [] anstelle von {} als Parameter für die Extend-Methode ):

var clonedNodesArray = jQuery.extend([], nodesArray);
Stef
quelle
2
Hmm, wenn Sie dies ablehnen, können Sie bitte einen Kommentar dazu hinzufügen, warum Sie dies tun? Oder können Sie zuerst den Code ausprobieren und sehen, ob er funktioniert oder nicht? Danke;)
Stef
1
Nach dem Ändern eines Objekts im ersten Array wird das Objekt im zweiten Array geändert, sodass es nicht in Ordnung ist.
Spikolynn
6

Diese Methode ist sehr einfach und Sie können Ihren Klon ändern, ohne das ursprüngliche Array zu ändern.

// Original Array
let array = [{name: 'Rafael'}, {name: 'Matheus'}];

// Cloning Array
let clone = array.map(a => {return {...a}})

// Editing the cloned array
clone[1].name = 'Carlos';


console.log('array', array)
// [{name: 'Rafael'}, {name: 'Matheus'}]

console.log('clone', clone)
// [{name: 'Rafael'}, {name: 'Carlos'}]

Rafael Grilli
quelle
1
Dies macht eine flache Kopie , die tief zwei Ebenen ist, während [...oldArray]und oldArray.slice(0)tun eine flache eine Ebene tiefer zu kopieren. Das ist also super nützlich, aber kein wirklich tiefer Klon.
Ben Wheeler
Ein echter Deep Clone kann mit lodash.clonedeepnpm erstellt werden
revelt
5

Wie Daniel Lew erwähnte, haben zyklische Graphen einige Probleme. Wenn ich dieses Problem hätte, würde ich entweder clone()den problematischen Objekten spezielle Methoden hinzufügen oder mich daran erinnern, welche Objekte ich bereits kopiert habe.

Ich würde es mit einer Variablen machen, copyCountdie sich jedes Mal um 1 erhöht, wenn Sie Ihren Code kopieren. Ein Objekt, das niedriger copyCountals der aktuelle Kopiervorgang ist, wird kopiert. Wenn nicht, sollte auf die bereits vorhandene Kopie verwiesen werden. Dies macht es notwendig, vom Original auf seine Kopie zu verlinken.

Es gibt noch ein Problem: Speicher. Wenn Sie diese Referenz von einem Objekt zum anderen haben, kann der Browser diese Objekte wahrscheinlich nicht freigeben, da immer von irgendwoher auf sie verwiesen wird. Sie müssten einen zweiten Durchgang machen, bei dem Sie alle Kopierreferenzen auf Null setzen. (Wenn Sie dies tun, müssten Sie keinen haben, copyCountaber ein Boolescher isCopiedWert würde ausreichen, da Sie den Wert im zweiten Durchgang zurücksetzen können.)

Georg Schölly
quelle
4

Array.slice kann verwendet werden, um ein Array oder einen Teil eines Arrays zu kopieren. Http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html Dies würde mit Zeichenfolgen und Zahlen funktionieren. - Ändern einer Zeichenfolge in Ein Array würde das andere nicht beeinflussen - aber Objekte werden immer noch nur als Referenz kopiert, sodass Änderungen an referenzierten Objekten in einem Array Auswirkungen auf das andere Array haben würden.

Hier ist ein Beispiel für einen JavaScript-Rückgängig-Manager, der hierfür hilfreich sein könnte: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx

markt
quelle
Ich kenne. Der Grund, warum ich dies implementieren wollte, ist, dass ich versuche, ein CSP-Problem mit Backtracking zu lösen. Ich dachte, dass eine der Möglichkeiten zum Implementieren von Backtracking darin bestehen könnte, den Status der Zuweisung der Variablen durch "Klonen" zu erfassen, indem ... solche Snapshots in einen Stapel geklont werden.
Wallyqs
... und nun, es könnte tatsächlich eine sehr schlechte Idee sein.
Wallyqs
Dieser Ansatz könnte andere Synchronisationskomplikationen haben :) .. Woher wissen Sie, dass das Array nicht geändert wird, während Sie einen Schnappschuss machen?
März
Es wurde ein Link zu einem Artikel hinzugefügt, in dem der Autor einen einfachen Rückgängig-Manager mit Javascript implementiert hat.
März
4

Mein Ansatz:

var temp = { arr : originalArray };
var obj = $.extend(true, {}, temp);
return obj.arr;

gibt mir einen schönen, sauberen, tiefen Klon des ursprünglichen Arrays - wobei keines der Objekte auf das Original zurück verwiesen wird :-)

Nebel
quelle
Dies ist die beste Lösung mit jquery. kurz und bündig.
John Henckel
1
Ich habe einen Leistungstest durchgeführt und diese Lösung scheint ungefähr 2x schneller zu sein als die JSON.stringify-Lösung.
Meehocz
4

lodash hat folgende cloneDeepFunktion:

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
DicBrus
quelle
4

Wenn Sie einen tiefen Klon implementieren möchten, verwenden Sie JSON.parse (JSON.stringify (Ihr {} oder [])).

const myObj ={
    a:1,
    b:2,
    b:3
}

const deepClone=JSON.parse(JSON.stringify(myObj));
deepClone.a =12;
console.log("deepClone-----"+myObj.a);
const withOutDeepClone=myObj;
withOutDeepClone.a =12;
console.log("withOutDeepClone----"+myObj.a);

Sudheer Nunna
quelle
3

Vergiss eval () (ist die am häufigsten missbrauchte Funktion von JS und verlangsamt den Code) und Slice (0) (funktioniert nur für einfache Datentypen)

Dies ist die beste Lösung für mich:

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

Ich war ziemlich frustriert von diesem Problem. Anscheinend tritt das Problem auf, wenn Sie ein generisches Array an die Methode $ .extend senden. Um dies zu beheben, habe ich eine kleine Überprüfung hinzugefügt, die perfekt mit generischen Arrays, jQuery-Arrays und allen Objekten funktioniert.

jQuery.extend({
    deepclone: function(objThing) {
        // return jQuery.extend(true, {}, objThing);
        /// Fix for arrays, without this, arrays passed in are returned as OBJECTS! WTF?!?!
        if ( jQuery.isArray(objThing) ) {
            return jQuery.makeArray( jQuery.deepclone($(objThing)) );
        }
        return jQuery.extend(true, {}, objThing);
    },
});

Rufen Sie auf mit:

var arrNewArrayClone = jQuery.deepclone(arrOriginalArray);
// Or more simply/commonly
var arrNewArrayClone = $.deepclone(arrOriginalArray);
Bremse
quelle
Deepclone? Ich benutze jquery-1.9.1 und es unterstützt diese Methode nicht. Ist es Methode der moderneren Version?
user5260143
@ user2783091 er erweitert JQuery, um diese Funktion hinzuzufügen. Es ist nicht etwas, das aus der Box kommt
JorgeeFG
3

Dadurch werden Arrays, Objekte, Null- und andere Skalarwerte tiefgreifend kopiert und alle Eigenschaften für nicht native Funktionen tiefgreifend kopiert (was ziemlich ungewöhnlich, aber möglich ist). (Aus Effizienzgründen versuchen wir nicht, nicht numerische Eigenschaften auf Arrays zu kopieren.)

function deepClone (item) {
  if (Array.isArray(item)) {
    var newArr = [];
    for (var i = item.length; i-- > 0;) {
      newArr[i] = deepClone(item[i]);
    }
    return newArr;
  }
  if (typeof item === 'function' && !(/\(\) \{ \[native/).test(item.toString())) {
    var obj;
    eval('obj = '+ item.toString());
    for (var k in item) {
      obj[k] = deepClone(item[k]);
    }
    return obj;
  }
  if (item && typeof item === 'object') {
    var obj = {};
    for (var k in item) {
      obj[k] = deepClone(item[k]);
    }
    return obj;
  }
  return item;
}
Brett Zamir
quelle
3

Ich verwende die neue ECMAScript 6 Object.assign- Methode:

let oldObject = [1,3,5,"test"];
let newObject = Object.assign({}, oldObject);

Das erste Argument dieser Methode ist das zu aktualisierende Array. Wir übergeben ein leeres Objekt, weil wir ein neues Objekt haben möchten.

Wir können auch diese Syntax verwenden, die dieselbe ist, aber kürzer:

let newObject = [...oldObject];
Chtiwi Malek
quelle
Beachten Sie, dass diese Ansätze nur Referenzen für Arrays und Objekte innerhalb des Arrays kopieren und keine neuen Kopien davon erstellen. Erwarten Sie, dass dies für mehrdimensionale Strukturen unterbrochen wird.
Ben Wheeler
2

Wir können eine einfache rekursive Array-Methode erfinden, um mehrdimensionale Arrays zu klonen. Während die Objekte in den verschachtelten Arrays ihren Verweis auf die entsprechenden Objekte im Quellarray beibehalten, werden Arrays dies nicht tun.

Array.prototype.clone = function(){
  return this.map(e => Array.isArray(e) ? e.clone() : e);
};

var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
    brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));

Reduzieren
quelle
2

In JavaScript ändern Array- und Objektkopien die Ursprungswerte, daher ist Deep Copy die Lösung dafür.

Eine tiefe Kopie bedeutet, tatsächlich ein neues Array zu erstellen und über die Werte zu kopieren, da alles, was damit passiert, niemals den ursprünglichen beeinflusst.

JSON.parseund JSON.stringifyist der beste und einfachste Weg zum Deep Copy. Die JSON.stringify()Methode konvertiert einen JavaScript-Wert in eine JSON-Zeichenfolge. Die JSON.parse()Methode analysiert eine JSON-Zeichenfolge und erstellt den durch die Zeichenfolge beschriebenen JavaScript-Wert oder das Objekt.

// Deep Clone

let a = [{ x:{z:1} , y: 2}];
let b = JSON.parse(JSON.stringify(a));
b[0].x.z=0

console.log(JSON.stringify(a)); //[{"x":{"z":1},"y":2}]
console.log(JSON.stringify(b)); // [{"x":{"z":0},"y":2}]

Für weitere Details: Lesen Sie hier

Bijay Rai
quelle
1
Dies ist die beste Lösung. Vielen Dank.
Nikolay
1

mit jQuery:

var target= [];
$.each(source, function() {target.push( $.extend({},this));});
lujan99
quelle
1

Der folgende Code führt rekursiv ein tiefes Kopieren von Objekten und Arrays durch :

function deepCopy(obj) {
if (Object.prototype.toString.call(obj) === '[object Array]') {
    var out = [], i = 0, len = obj.length;
    for ( ; i < len; i++ ) {
        out[i] = arguments.callee(obj[i]);
    }
    return out;
}
if (typeof obj === 'object') {
    var out = {}, i;
    for ( i in obj ) {
        out[i] = arguments.callee(obj[i]);
    }
    return out;
}
return obj;
}

Quelle

Franck Dernoncourt
quelle
arguments.calleeist im strengen Modus nicht verfügbar und hat ansonsten Leistungsprobleme.
Brett Zamir
0

Ich denke, es ist gelungen, eine generische Methode zum Deep Cloning von JavaScript-Strukturen zu schreiben, die hauptsächlich von Object.createallen modernen Browsern unterstützt wird. Der Code lautet wie folgt:

function deepClone (item) {
  if (Array.isArray(item)) {
    var newArr = [];

    for (var i = item.length; i-- !== 0;) {
      newArr[i] = deepClone(item[i]);
    }

    return newArr;
  }
  else if (typeof item === 'function') {
    eval('var temp = '+ item.toString());
    return temp;
  }
  else if (typeof item === 'object')
    return Object.create(item);
  else
    return item;
}
Ozantunca
quelle
Object.createwird itemals Prototyp des Objekts behandelt , aber das unterscheidet sich vom Klonen. Wenn itemes geändert wird, werden Änderungen in seinem "Klon" wiedergegeben und umgekehrt. Dieser Ansatz funktioniert nicht.
Brett Zamir
0

Zum Klonen der Objekte wollte ich nur ECMAScript 6 vorschlagen reduce():

const newArray=myArray.reduce((array, element)=>array.push(Object.assign({}, element)), []);

Aber ehrlich gesagt gefällt mir die Antwort von @dinodsaurus noch besser. Ich stelle diese Version hier nur als weitere Option ein, aber ich persönlich werde sie verwenden, map()wie von @dinodsaurus vorgeschlagen.

Garret Wilson
quelle
0

Je nachdem, ob Sie Underscore oder Babel haben, finden Sie hier einen Benchmark für die unterschiedliche Art des Deep Cloning eines Arrays.

https://jsperf.com/object-rest-spread-vs-clone/2

Sieh aus, als wäre Babel am schnellsten.

var x = babel({}, obj)
Romuald
quelle
0
       var game_popularity = [
            { game: "fruit ninja", popularity: 78 },
            { game: "road runner", popularity: 20 },
            { game: "maze runner", popularity: 40 },
            { game: "ludo", popularity: 75 },
            { game: "temple runner", popularity: 86 }
        ];
        console.log("sorted original array before clonning");
        game_popularity.sort((a, b) => a.popularity < b.popularity);
        console.log(game_popularity);


        console.log("clone using object assign");
        const cl2 = game_popularity.map(a => Object.assign({}, a));
        cl2[1].game = "clash of titan";
        cl2.push({ game: "logan", popularity: 57 });
        console.log(cl2);


        //adding new array element doesnt reflect in original array
        console.log("clone using concat");
        var ph = []
        var cl = ph.concat(game_popularity);

        //copied by reference ?
        cl[0].game = "rise of civilization";

        game_popularity[0].game = 'ping me';
        cl.push({ game: "angry bird", popularity: 67 });
        console.log(cl);

        console.log("clone using ellipses");
        var cl3 = [...game_popularity];
        cl3.push({ game: "blue whale", popularity: 67 });
        cl3[2].game = "harry potter";
        console.log(cl3);

        console.log("clone using json.parse");
        var cl4 = JSON.parse(JSON.stringify(game_popularity));
        cl4.push({ game: "home alone", popularity: 87 });
        cl4[3].game ="lockhead martin";
        console.log(cl4);

        console.log("clone using Object.create");
        var cl5 = Array.from(Object.create(game_popularity));
        cl5.push({ game: "fish ville", popularity: 87 });
        cl5[3].game ="veto power";
        console.log(cl5);


        //array function
        console.log("sorted original array after clonning");
        game_popularity.sort((a, b) => a.popularity < b.popularity);
        console.log(game_popularity);


        console.log("Object.assign deep clone object array");
        console.log("json.parse deep clone object array");
        console.log("concat does not deep clone object array");
        console.log("ellipses does not deep clone object array");
        console.log("Object.create does not deep clone object array");


        Output:


        sorted original array before clonning
        [ { game: 'temple runner', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 } ]
        clone using object assign
        [ { game: 'temple runner', popularity: 86 },
        { game: 'clash of titan', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'logan', popularity: 57 } ]
        clone using concat
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'ludo', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'angry bird', popularity: 67 } ]
        clone using ellipses
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'maze runner', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'blue whale', popularity: 67 } ]
        clone using json.parse
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'lockhead martin', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'home alone', popularity: 87 } ]
        clone using Object.create
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'veto power', popularity: 40 },
        { game: 'road runner', popularity: 20 },
        { game: 'fish ville', popularity: 87 } ]
        sorted original array after clonning
        [ { game: 'ping me', popularity: 86 },
        { game: 'fruit ninja', popularity: 78 },
        { game: 'harry potter', popularity: 75 },
        { game: 'veto power', popularity: 40 },
        { game: 'road runner', popularity: 20 } ]

        Object.assign deep clone object array
        json.parse deep clone object array
        concat does not deep clone object array
        ellipses does not deep clone object array
        Object.create does not deep clone object array
Sangram
quelle