Aktualisierung 2022
Es gibt einen neuen JS-Standard namens "strukturiertes Klonen". Er funktioniert in allen Browsern:
const clone = structuredClone(object);
Alte Antwort
Dies für ein beliebiges Objekt in JavaScript zu tun, ist weder einfach noch unkompliziert. Sie werden auf das Problem stoßen, dass Sie fälschlicherweise Attribute aus dem Prototyp des Objekts übernehmen, die im Prototyp belassen und nicht in die neue Instanz kopiert werden sollten. Wenn Sie z. B. ein clone
Methode zu Object.prototype
wie in einigen Antworten beschrieben, müssen Sie dieses Attribut explizit auslassen. Aber was ist, wenn es noch andere zusätzliche Methoden gibt, die zu Object.prototype
oder andere Zwischenprototypen, von denen Sie nichts wissen? In diesem Fall werden Sie Attribute kopieren, die Sie nicht kopieren sollten, daher müssen Sie unvorhergesehene, nicht-lokale Attribute mit der hasOwnProperty
méthode.
Zusätzlich zu den nicht aufzählbaren Attributen werden Sie auf ein schwierigeres Problem stoßen, wenn Sie versuchen, Objekte zu kopieren, die versteckte Eigenschaften haben. Zum Beispiel, prototype
ist eine verborgene Eigenschaft einer Funktion. Außerdem wird der Prototyp eines Objekts mit dem Attribut __proto__
die ebenfalls ausgeblendet ist und von einer for/in-Schleife, die über die Attribute des Quellobjekts iteriert, nicht kopiert wird. Ich denke __proto__
kann spezifisch für den JavaScript-Interpreter von Firefox sein, und in anderen Browsern kann es etwas anderes sein, aber Sie verstehen 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 entdecken.
Ein weiterer Stolperstein auf der Suche nach einer eleganten Lösung ist das Problem der korrekten Einrichtung der Prototyp-Vererbung. Wenn der Prototyp Ihres Quellobjekts Object
und dann einfach ein neues allgemeines Objekt mit {}
wird funktionieren, aber wenn der Prototyp der Quelle ein Nachkomme von Object
dann fehlen Ihnen die zusätzlichen Mitglieder des Prototyps, die Sie mit der Option hasOwnProperty
Filter, oder die im Prototyp enthalten waren, aber von vornherein nicht aufzählbar waren. Eine Lösung könnte darin bestehen, das Quellobjekt aufzurufen constructor
Eigenschaft verwenden, um das anfängliche Kopierobjekt zu erhalten und dann die Attribute zu kopieren, aber dann erhalten Sie immer noch keine nicht aufzählbaren Attribute. Zum Beispiel, ein Date
Objekt speichert seine Daten als verborgenes Mitglied:
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);
Die Datumszeichenfolge für d1
liegt 5 Sekunden hinter dem von d2
. Eine Möglichkeit zur Herstellung einer Date
dasselbe wie ein anderer ist, indem man die setTime
Methode, aber das ist spezifisch für die Date
Klasse. Ich glaube nicht, dass es eine allgemein gültige Lösung für dieses Problem gibt, aber ich würde mich freuen, wenn ich falsch liege!
Als ich das allgemeine tiefe Kopieren implementieren musste, ging ich schließlich einen Kompromiss ein, indem ich annahm, dass ich nur eine einfache Object
, Array
, Date
, String
, Number
, oder Boolean
. Die letzten 3 Typen sind unveränderlich, so dass ich eine flache Kopie durchführen konnte und mir keine Sorgen machen musste, dass sie sich ändert. Außerdem nahm ich an, dass alle Elemente, die in Object
o Array
wäre auch einer der 6 einfachen Typen in dieser Liste. Dies kann mit Code wie dem folgenden erreicht werden:
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.");
}
Die obige Funktion ist für die 6 genannten einfachen Typen geeignet, 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:
// 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;
Es kann nicht mit jedem JavaScript-Objekt umgehen, aber es kann für viele Zwecke ausreichen, solange man nicht davon ausgeht, dass es einfach für alles funktioniert, was man ihm hinwirft.
35 Stimmen
Siehe diese Frage: stackoverflow.com/questions/122102/
0 Stimmen
Unterstützen Sie auf jeden Fall @Niyaz! Shortlink: tinyurl.com/JSCopyObject
290 Stimmen
Für JSON verwende ich
mObj=JSON.parse(JSON.stringify(jsonObject));
79 Stimmen
Ich verstehe wirklich nicht, warum niemand vorschlägt.
Object.create(o)
dass es alles tut, was der Autor verlangt?5 Stimmen
@froginvasion Wahrscheinlich, weil es im IE8 und darunter nicht unterstützt wird.
4 Stimmen
@Wynand Das ist überhaupt kein gutes Argument. Es gibt eine Menge Polyfills für
Object.create
die zum Beispiel gefunden werden können: refheap.com/900061 Stimmen
@froginvasion In Ordnung, obwohl ich argumentieren könnte, dass der Auftraggeber eine "elegante" [ sic und nicht jeder würde notwendigerweise zustimmen, dass die Verwendung eines Polyfills dieser Beschreibung entspricht. Ich habe nur versucht, Ihnen Folgendes mitzuteilen a möglicher Grund dafür
Object.create
wurde nicht vorgeschlagen (falls dies der Fall ist), weshalb ich "wahrscheinlich" schrieb. Unabhängig davon bin ich für Polyfills und habe mir vor kurzem Folgendes angesehen diese eine, die übrigens ähnlich wie Ihr Schnipsel ist. Wenn Sie ein besseres Feedback wünschen, könnten Sie Ihren Vorschlag auch als Antwort hinzufügen.2 Stimmen
Object.create eignet sich hervorragend, wenn Sie den Prototyp Ihres Objekts kopieren möchten.
59 Stimmen
var x = { deep: { key: 1 } }; var y = Object.create(x); x.deep.key = 2;
Nachdem Sie dies getan haben,y.deep.key
wird auch 2 sein, daher kann Object.create NICHT zum Klonen verwendet werden...1 Stimmen
@froginvasion - weil es nicht einmal für flache Objekte funktioniert? (Chrome 45). Du bekommst einfach
__proto__
nicht ein Klon...2 Stimmen
Object.create
bekommt man nicht__proto__
wird ein neues Objekt erzeugt, dessen Prototyp auf das Argument verweist, wodurch eine Kette entsteht. Ich stimme zu, dass es sich vielleicht nicht um einen echten "Klon" im traditionellen Sinne handelt, aber je nach SituationObject.create
ist viel konsistenter als die verschiedenen Klontechniken, die im Folgenden verwendet werden. developer.mozilla.org/de-US/docs/Web/JavaScript/Reference/1 Stimmen
Wie wäre es mit
var newObj = (function(){ return oldObj; }());
23 Stimmen
@r3wt das wird nicht funktionieren... Bitte posten Sie erst, nachdem Sie einen grundlegenden Test der Lösung durchgeführt haben...
2 Stimmen
Hier ein Benchmark von verschiedenen Lösungen: jsben.ch/#/bWfk9
0 Stimmen
@RubenStolk warum kann OP das Objekt nicht in eine neue Variable speichern?
var copyobject=object
??4 Stimmen
@Mahi Dadurch wird das Objekt nicht kopiert. Es wird eine neue Variable erstellt, die auf das gleiche Objekt verweist.
0 Stimmen
@LordLoh. Was ist, wenn Sie in einer Javascript-Umgebung sind, in der Sie keine Bibliotheken wie JSON importieren können. Apples Quartz Composer Editor zum Beispiel, nicht sicher über Adobe CC Scripting.
1 Stimmen
developer.mozilla.org/de-US/docs/Web/JavaScript/Reference/ - Ich habe das gerade mit dem Chrome-Entwickler-Terminal ausprobiert -
oj1={}; oj1.p1=222; oj2={}; Object.assign(oj2,oj1); oj2.p1=555; oj1.p1;
- wird dies zeigen222
Auch hier wird geantwortet: stackoverflow.com/a/36177142/4821760 Stimmen
@LordLoh. Anscheinend kann ich JSON.parse und JSON.stringify doch innerhalb von QC aufrufen. Core Funktionen aufrufen. Auch habe ich dieses Polyfill auf der Referenzseite und Links zu erweiterten Polyfills JSON2 und JSON3 gefunden: developer.mozilla.org/de-US/docs/Web/JavaScript/Reference/
3 Stimmen
{...original}
6 Stimmen
Wenn Sie Object.create() vorschlagen, dann wissen Sie sehr wenig über JS. Mit Object.create wird das Objekt X nicht geklont. Y = Object.create(X) tut dies und nichts weiter: Es wird ein neues Objekt Y mit X als Prototyp erstellt. Das Objekt X wird zum Prototyp von Objekt Y. Das ist nicht das, was Sie wollen. Ganz und gar nicht. Da die Methoden und Daten von X nicht nach Y kopiert werden, sondern referenziert werden, enthält Y eine Referenz auf die Daten und Methoden von X. Wie falsch kann man liegen!?
0 Stimmen
Kürzlich beantwortete es über aquí
0 Stimmen
Ver developer.mozilla.org's JavaScript/Referenz von assign#Deep_Clone .
0 Stimmen
Dadurch sollte eine Kopie erstellt werden:
let y = {...x};
0 Stimmen
Sie können die Clone-Methode von Lodash oder den Spread-Operator verwenden let x = {} let y = {irgendein Wert} x = {...x, ...y}
0 Stimmen
stackoverflow.com/questions/38416020/