Ich habe ein Objekt x
. Ich möchte es als Objekt kopieren y
, so dass Änderungen y
nicht geändert werden x
. Ich habe festgestellt, dass das Kopieren von Objekten, die von integrierten JavaScript-Objekten abgeleitet sind, zu zusätzlichen, unerwünschten Eigenschaften führt. Dies ist kein Problem, da ich eines meiner wörtlich konstruierten Objekte kopiere.
Wie klone ich ein JavaScript-Objekt richtig?
javascript
clone
javascript-objects
soundly_typed
quelle
quelle
mObj=JSON.parse(JSON.stringify(jsonObject));
Object.create(o)
, es macht alles, was der Autor verlangt?var x = { deep: { key: 1 } }; var y = Object.create(x); x.deep.key = 2;
Danachy.deep.key
wird auch 2 sein, daher kann Object.create NICHT zum Klonen verwendet werden ...Antworten:
Dies für ein Objekt in JavaScript zu tun, ist nicht einfach oder unkompliziert. Sie werden auf das Problem stoßen, fälschlicherweise Attribute aus dem Prototyp des Objekts zu übernehmen, die im Prototyp verbleiben und nicht in die neue Instanz kopiert werden sollten. Wenn Sie beispielsweise eine
clone
Methode hinzufügenObject.prototype
, wie einige Antworten zeigen, müssen Sie dieses Attribut explizit überspringen. Aber was ist, wenn andere zusätzliche MethodenObject.prototype
oder andere Zwischenprototypen hinzugefügt werden , von denen Sie nichts wissen? In diesem Fall kopieren Sie Attribute, die Sie nicht sollten, sodass Sie unvorhergesehene, nicht lokale Attribute mit derhasOwnProperty
Methode erkennen müssen.Zusätzlich zu nicht aufzählbaren Attributen tritt ein schwierigeres Problem auf, wenn Sie versuchen, Objekte mit versteckten Eigenschaften zu kopieren. Ist beispielsweise
prototype
eine versteckte Eigenschaft einer Funktion. Außerdem wird auf den Prototyp eines Objekts mit dem Attribut verwiesen__proto__
, das ebenfalls ausgeblendet ist, und nicht von einer for / in-Schleife kopiert, die über die Attribute des Quellobjekts iteriert. Ich denke, es__proto__
könnte spezifisch für den JavaScript-Interpreter von Firefox sein und in anderen Browsern etwas anderes, aber Sie erhalten das Bild. Nicht alles ist aufzählbar. Sie können ein verstecktes Attribut kopieren, wenn Sie seinen Namen kennen, aber ich kenne keine Möglichkeit, es automatisch zu erkennen.Ein weiterer Haken bei der Suche nach einer eleganten Lösung ist das Problem, die Vererbung des Prototyps korrekt einzurichten. Wenn der Prototyp Ihres Quellobjekts so ist
Object
,{}
funktioniert das einfache Erstellen eines neuen allgemeinen Objekts mit. Wenn der Prototyp der Quelle jedoch ein Nachkomme von istObject
, fehlen Ihnen die zusätzlichen Elemente des Prototyps, den Sie mithilfe deshasOwnProperty
Filters übersprungen haben oder den waren im Prototyp, aber überhaupt nicht aufzählbar. Eine Lösung könnte darin bestehen, dieconstructor
Eigenschaft des Quellobjekts aufzurufen , um das ursprüngliche Kopierobjekt abzurufen und dann über die Attribute zu kopieren. Dann erhalten Sie jedoch immer noch keine nicht aufzählbaren Attribute. EinDate
Objekt speichert beispielsweise seine Daten als verstecktes Element:Die Datumszeichenfolge für
d1
liegt 5 Sekunden hinter der vond2
. Eine Möglichkeit, eine mitDate
der anderen zu vergleichen, besteht darin, diesetTime
Methode aufzurufen. Dies ist jedoch spezifisch für dieDate
Klasse. Ich glaube nicht, dass es eine kugelsichere allgemeine Lösung für dieses Problem gibt, obwohl ich gerne falsch liegen würde!Als ich hatte General tief zu implementieren Kopiere ich durch die Annahme zu gefährden endete , dass ich nur eine Ebene zu kopieren brauchen würde
Object
,Array
,Date
,String
,Number
, oderBoolean
. Die letzten 3 Typen sind unveränderlich, so dass ich eine flache Kopie erstellen und mir keine Sorgen machen könnte, dass sie sich ändert. Ich ging weiter davon aus, dass alle Elemente, die in einer der 6 einfachen Typen in dieser Liste enthalten sindObject
oderArray
auch sein würden. Dies kann mit Code wie dem folgenden erreicht werden:Die obige Funktion funktioniert für die 6 einfachen Typen, die ich erwähnt habe, angemessen, solange die Daten in den Objekten und Arrays eine Baumstruktur bilden. Das heißt, es gibt nicht mehr als einen Verweis auf dieselben Daten im Objekt. Zum Beispiel:
Es kann kein JavaScript-Objekt verarbeiten, kann jedoch für viele Zwecke ausreichen, solange Sie nicht davon ausgehen, dass es nur für alles funktioniert, was Sie darauf werfen.
quelle
JSON.parse(JSON.stringify([some object]),[some revirer function])
eine Lösung?var cpy = new obj.constructor()
?Wenn Sie
Date
in Ihrem Objekt keine s, Funktionen, undefined, regExp oder Infinity verwenden, ist ein sehr einfacher EinzeilerJSON.parse(JSON.stringify(object))
:Dies funktioniert für alle Arten von Objekten, die Objekte, Arrays, Zeichenfolgen, Boolesche Werte und Zahlen enthalten.
Siehe auch diesen Artikel über den strukturierten Klonalgorithmus von Browsern, der beim Posten von Nachrichten an und von einem Worker verwendet wird. Es enthält auch eine Funktion zum tiefen Klonen.
quelle
Mit jQuery können Sie flache Kopien mit verlängern :
Nachträgliche Änderungen am
copiedObject
werden sich nicht auf das auswirkenoriginalObject
und umgekehrt.Oder um eine tiefe Kopie zu machen :
quelle
var copiedObject = jQuery.extend({},originalObject);
jQuery.extend(true, {}, originalObject);
...subsequent changes to the copiedObject will not affect the originalObject, and vice versa...
. Entschuldigung, dass ich wirklich verwirrt war.In ECMAScript 6 gibt es die Object.assign- Methode, mit der Werte aller aufzählbaren eigenen Eigenschaften von einem Objekt in ein anderes kopiert werden. Zum Beispiel:
Beachten Sie jedoch, dass verschachtelte Objekte weiterhin als Referenz kopiert werden.
quelle
Object.assign
ist der richtige Weg. Es ist auch einfach, es zu füllenPro MDN :
Object.assign({}, a)
JSON.parse(JSON.stringify(a))
Es sind keine externen Bibliotheken erforderlich, Sie müssen jedoch zuerst die Browserkompatibilität überprüfen .
quelle
clone
Funktionalität hat. Weitere Informationen finden SieEs gibt viele Antworten, aber keine, die Object.create erwähnt aus ECMAScript 5 erwähnt, das Ihnen zwar keine exakte Kopie gibt, aber die Quelle als Prototyp des neuen Objekts festlegt.
Dies ist also keine genaue Antwort auf die Frage, aber es ist eine einzeilige Lösung und somit elegant. Und es funktioniert am besten für 2 Fälle:
Beispiel:
Warum halte ich diese Lösung für überlegen? Es ist nativ, also keine Schleife, keine Rekursion. Ältere Browser benötigen jedoch eine Polyfüllung.
quelle
var a = {b:'hello',c:{d:'world'}}, b = Object.create(a); a == b /* false */; a.c == b.c /* true */;
Object.create
verweist durch Verweise auf die Eigenschaften des Elternteils. Wenn sich die Eigenschaftswerte des Elternteils ändern, ändert sich auch das des Kindes. Dies hat einige überraschende Nebenwirkungen bei verschachtelten Arrays und Objekten, die zu schwer zu findenden Fehlern in Ihrem Code führen können, wenn Sie diese nicht kennen: jsbin.com/EKivInO/2 . Ein geklontes Objekt ist ein völlig neues, unabhängiges Objekt, das dieselben Eigenschaften und Werte wie das übergeordnete Objekt hat, jedoch nicht mit dem übergeordneten Objekt verbunden ist.Eine elegante Möglichkeit, ein Javascript-Objekt in einer Codezeile zu klonen
Eine
Object.assign
Methode ist Teil des ECMAScript 2015 (ES6) -Standards und macht genau das, was Sie brauchen.Weiterlesen...
Die Polyfüllung zur Unterstützung älterer Browser:
quelle
Object.assign
zwei Parameter verwendet, wenn dievalue
Funktion in der Polyfüllung nur einen Parameter akzeptiert?arguments
vorher nicht mit dem Objekt vertraut .) Ich habe Probleme, esObject()
über Google zu finden ... es ist eine Typografie, nicht wahr?Bei den meisten Lösungen im Internet gibt es mehrere Probleme. Deshalb habe ich mich für ein Follow-up entschieden, das beinhaltet, warum die akzeptierte Antwort nicht akzeptiert werden sollte.
Ausgangssituation
Ich möchte ein Javascript mit all seinen Kindern und ihren Kindern und so weiter tief kopieren
Object
. Da ich aber nicht Art eines normalen Entwickler bin, meineObject
hat normaleproperties
,circular structures
und sogarnested objects
.Also lasst uns ein
circular structure
und einnested object
erstes erstellen .Lassen Sie uns alles in einem
Object
Namen zusammenbringena
.Als nächstes wollen wir
a
in eine Variable mit dem Namen kopierenb
und sie mutieren.Sie wissen, was hier passiert ist, denn wenn nicht, würden Sie nicht einmal auf diese großartige Frage stoßen.
Lassen Sie uns nun eine Lösung finden.
JSON
Der erste Versuch, den ich versuchte, war mit
JSON
.Verschwenden Sie nicht zu viel Zeit damit
TypeError: Converting circular structure to JSON
.Rekursive Kopie (die akzeptierte "Antwort")
Werfen wir einen Blick auf die akzeptierte Antwort.
Sieht gut aus, oder? Es ist eine rekursive Kopie des Objekts und behandelt auch andere Typen
Date
, aber das war keine Voraussetzung.Rekursion und
circular structures
funktioniert nicht gut zusammen ...RangeError: Maximum call stack size exceeded
native Lösung
Nachdem ich mit meinem Kollegen gestritten hatte, fragte mich mein Chef, was passiert sei, und er fand nach einigem googeln eine einfache Lösung . Es heißt
Object.create
.Diese Lösung wurde vor einiger Zeit zu Javascript hinzugefügt und funktioniert sogar
circular structure
.... und Sie sehen, es hat mit der verschachtelten Struktur im Inneren nicht funktioniert.
Polyfill für die native Lösung
Es gibt eine Polyfüllung für
Object.create
den älteren Browser, genau wie für den IE 8. Sie wird von Mozilla empfohlen, ist natürlich nicht perfekt und führt zum gleichen Problem wie die native Lösung .Ich habe den Bereich
F
außerhalb des Bereichs platziert, damit wir einen Blick darauf werfen können, wasinstanceof
uns sagt.Gleiches Problem wie bei der nativen Lösung , jedoch etwas schlechtere Ausgabe.
die bessere (aber nicht perfekte) Lösung
Beim Stöbern fand ich eine ähnliche Frage ( in Javascript, wenn ich eine tiefe Kopie durchführe, wie vermeide ich einen Zyklus, weil eine Eigenschaft "dies" ist? ) Zu dieser Frage , aber mit einer viel besseren Lösung.
Und schauen wir uns die Ausgabe an ...
Die Anforderungen stimmen überein, aber es gibt noch einige kleinere Probleme, einschließlich des Änderns
instance
vonnested
undcirc
zuObject
.Fazit
Die letzte Lösung mit Rekursion und Cache ist möglicherweise nicht die beste, aber es handelt sich um eine echte Kopie des Objekts. Es behandelt einfach
properties
,circular structures
undnested object
, aber es wird vermasseln die Instanz von ihnen während klonen.jsfiddle
quelle
Wenn Sie mit einer flachen Kopie einverstanden sind, verfügt die Bibliothek underscore.js über eine Klonmethode .
oder Sie können es wie erweitern
quelle
OK, stellen Sie sich vor, Sie haben dieses Objekt unten und möchten es klonen:
oder
Die Antwort hängt hauptsächlich davon ab, welches ECMA-Skript Sie verwenden. In
ES6+
können Sie einfachObject.assign
den Klon erstellen :oder mit einem Spread-Operator wie folgt:
Wenn Sie jedoch verwenden
ES5
, können Sie nur wenige Methoden verwenden.JSON.stringify
Stellen Sie jedoch sicher, dass Sie nicht einen großen Datenblock zum Kopieren verwenden. In vielen Fällen kann dies jedoch eine praktische Zeile sein:quelle
big chunk of data
gleichbedeutend wäre? 100kb? 100 MB? Vielen Dank!Object.assign
macht eine flache Kopie (genau wie die Verbreitung, @Alizera)Eine besonders unelegante Lösung ist die Verwendung der JSON-Codierung, um tiefe Kopien von Objekten zu erstellen, die keine Mitgliedsmethoden haben. Die Methode besteht darin, Ihr Zielobjekt mit JSON zu codieren. Durch Decodieren erhalten Sie dann die gesuchte Kopie. Sie können so oft dekodieren, wie Sie möchten, und so viele Kopien erstellen, wie Sie benötigen.
Natürlich gehören Funktionen nicht zu JSON, daher funktioniert dies nur für Objekte ohne Member-Methoden.
Diese Methode war perfekt für meinen Anwendungsfall, da ich JSON-Blobs in einem Schlüsselwertspeicher speichere und wenn sie als Objekte in einer JavaScript-API verfügbar gemacht werden, enthält jedes Objekt tatsächlich eine Kopie des ursprünglichen Status des Objekts kann das Delta berechnen, nachdem der Anrufer das exponierte Objekt mutiert hat.
quelle
{ 'foo': function() { return 1; } }
ist ein wörtlich erstelltes Objekt.Sie können einfach eine Spread-Eigenschaft verwenden, um ein Objekt ohne Referenzen zu kopieren. Aber seien Sie vorsichtig (siehe Kommentare), die 'Kopie' befindet sich nur auf der untersten Objekt- / Array-Ebene. Verschachtelte Eigenschaften sind immer noch Referenzen!
Kompletter Klon:
Klonen mit Referenzen auf der zweiten Ebene:
JavaScript unterstützt Deep Clones nativ nicht. Verwenden Sie eine Utility-Funktion. Zum Beispiel Ramda:
quelle
const first = {a: 'foo', b: 'bar'}; const second = {...{a} = first}
Für Benutzer von AngularJS gibt es auch eine direkte Methode zum Klonen oder Erweitern der Objekte in dieser Bibliothek.
oder
Mehr in der Dokumentation zu angle.copy ...
quelle
Hier ist eine Funktion, die Sie verwenden können.
quelle
new
. Die akzeptierte Antwort nicht.A. Levys Antwort ist fast vollständig, hier ist mein kleiner Beitrag: Es gibt eine Möglichkeit, mit rekursiven Referenzen umzugehen , siehe diese Zeile
if(this[attr]==this) copy[attr] = copy;
Wenn das Objekt ein XML-DOM-Element ist, müssen wir stattdessen cloneNode verwenden
if(this.cloneNode) return this.cloneNode(true);
Inspiriert von A. Levys umfassender Studie und Calvins Prototyping-Ansatz biete ich folgende Lösung an:
Siehe auch den Hinweis von Andy Burke in den Antworten.
quelle
Date.prototype.clone = function() {return new Date(+this)};
Aus diesem Artikel: So kopieren Sie Arrays und Objekte in Javascript von Brian Huisman:
quelle
var copiedObj = Object.create(obj);
ein guter Weg?In ES-6 können Sie einfach Object.assign (...) verwenden. Ex:
Eine gute Referenz finden Sie hier: https://googlechrome.github.io/samples/object-assign-es6/
quelle
let obj = {person: 'Thor Odinson'}; let clone = Object.assign({}, obj); clone.title = "Whazzup";
)obj
Eigenschaften primitiver Typen tatsächlich geklont werden. Eigenschaftswerte, die selbst Objekte sind, werden nicht geklont.In ECMAScript 2018
Beachten Sie, dass verschachtelte Objekte weiterhin als Referenz kopiert werden .
quelle
const objDeepClone = JSON.parse(JSON.stringify(obj));
Verwenden von Lodash:
quelle
_.cloneDeep(x)
da es im Wesentlichen das gleiche wie oben ist, aber besser liest.Interessiert am Klonen einfacher Objekte:
JSON.parse(JSON.stringify(json_original));
Quelle: Wie kopiere ich ein JavaScript-Objekt in eine neue Variable, NICHT als Referenz?
quelle
Sie können ein Objekt klonen und alle Verweise mit einer einzigen Codezeile aus dem vorherigen entfernen. Einfach machen:
Für Browser / Engines, die Object.create derzeit nicht unterstützen, können Sie diese Polyfüllung verwenden:
quelle
Object.create(...)
scheint definitiv der richtige Weg zu sein.Object.hasOwnProperty
? Auf diese Weise wissen die Benutzer, wie sie das Durchsuchen des Prototyp-Links verhindern können.text
Mitglied in obj2 beschatten. Sie erstellen keine Kopie, sondern verschieben sich nur auf die Prototypenkette, wenn ein Mitglied auf obj2 nicht gefunden wird.Neue Antwort auf eine alte Frage! Wenn Sie das Vergnügen haben, ECMAScript 2016 (ES6) mit Spread Syntax zu verwenden , ist dies ganz einfach.
Dies bietet eine saubere Methode für eine flache Kopie eines Objekts. Das Erstellen einer tiefen Kopie, dh das Erstellen einer neuen Kopie jedes Werts in jedem rekursiv verschachtelten Objekt, erfordert eine der oben genannten schwereren Lösungen.
JavaScript entwickelt sich weiter.
quelle
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
ES6-Lösung, wenn Sie eine Klasseninstanz und nicht nur ein Eigenschaftsobjekt (flach) klonen möchten .
quelle
let cloned = Object.assign({}, obj)
?Ich denke, es gibt eine einfache und funktionierende Antwort. Beim tiefen Kopieren gibt es zwei Bedenken:
Daher denke ich, dass eine einfache Lösung darin bestehen wird, zuerst zu serialisieren und zu deserialisieren und dann eine Zuweisung vorzunehmen, um auch Funktionen zu kopieren.
Obwohl diese Frage viele Antworten hat, hoffe ich, dass auch diese hilft.
quelle
cloneDeep
.Für eine tiefe Kopie und einen Klon JSON.stringify und dann JSON.parse das Objekt:
quelle
Dies ist eine Anpassung des Codes von A. Levy, um auch das Klonen von Funktionen und mehrere / zyklische Referenzen zu handhaben. Dies bedeutet, dass der geklonte Objektbaum diese hat, wenn zwei Eigenschaften im geklonten Baum Referenzen desselben Objekts sind Eigenschaften zeigen auf ein und denselben Klon des referenzierten Objekts. Dies löst auch den Fall von zyklischen Abhängigkeiten, die, wenn sie nicht behandelt werden, zu einer Endlosschleife führen. Die Komplexität des Algorithmus ist O (n)
Einige schnelle Tests
quelle
Ich wollte nur zu allen
Object.create
Lösungen in diesem Beitrag hinzufügen , dass dies mit nodejs nicht in der gewünschten Weise funktioniert.In Firefox das Ergebnis von
ist
{test:"test"}
.In nodejs ist es
quelle
Object.hasOwnProperty
zu überprüfen, ob Sie das Array besitzen oder nicht. Ja, dies erhöht die Komplexität bei der prototypischen Vererbung.quelle
if(!src && typeof src != "object"){
. Ich denke das sollte||
nicht sein&&
.Da mindeavour angegeben hat, dass das zu klonende Objekt ein "wörtlich konstruiertes" Objekt ist, könnte eine Lösung darin bestehen, das Objekt einfach mehrmals zu generieren, anstatt eine Instanz des Objekts zu klonen:
quelle
Ich habe meine eigene Implementierung geschrieben. Ich bin mir nicht sicher, ob es als bessere Lösung gilt:
Es folgt die Implementierung:
quelle