Tiefkopie
Eine Tiefkopie eines Objekts ist eine Kopie, deren Eigenschaften nicht dieselben Referenzen teilen (auf dieselben zugrunde liegenden Werte verweisen) wie die des Ausgangsobjekts, aus dem die Kopie erstellt wurde. Dadurch können Sie sicher sein, dass weder eine Änderung der Quelle noch der Kopie dazu führt, dass sich das andere Objekt ebenfalls ändert. Dieses Verhalten steht im Gegensatz zum Verhalten einer Flachkopie, bei der Änderungen an verschachtelten Eigenschaften in der Quelle oder der Kopie dazu führen können, dass sich das andere Objekt ebenfalls ändert.
Zwei Objekte o1
und o2
sind strukturell äquivalent, wenn ihr beobachtbares Verhalten dasselbe ist. Dieses Verhalten umfasst:
- Die Eigenschaften von
o1
undo2
haben dieselben Namen in derselben Reihenfolge. - Die Werte ihrer Eigenschaften sind strukturell äquivalent.
- Ihre Prototypenketten sind strukturell äquivalent (obwohl es sich bei der Betrachtung der strukturellen Äquivalenz normalerweise um einfache Objekte handelt, die beide von
Object.prototype
erben).
Strukturell äquivalente Objekte können entweder dasselbe Objekt sein (o1 === o2
) oder Kopien (o1 !== o2
). Da äquivalente primitive Werte immer als gleich verglichen werden, können Sie keine Kopien davon erstellen.
Wir können Tiefkopien nun formeller definieren als:
- Sie sind nicht dasselbe Objekt (
o1 !== o2
). - Die Eigenschaften von
o1
undo2
haben dieselben Namen in derselben Reihenfolge. - Die Werte ihrer Eigenschaften sind Tiefkopien voneinander.
- Ihre Prototypenketten sind strukturell äquivalent.
Tiefkopien können entweder ihre Prototypenketten kopiert haben oder nicht (häufig sind sie es nicht). Aber zwei Objekte mit strukturell nicht äquivalenten Prototypenketten (zum Beispiel eines ist ein Array und das andere ein einfaches Objekt) sind niemals Kopien voneinander.
Die Kopie eines Objekts, dessen Eigenschaften alle primitive Werte haben, entspricht sowohl der Definition einer Tiefkopie als auch einer Flachkopie. Es ist jedoch wenig sinnvoll, in einem solchen Fall von der Tiefe einer Kopie zu sprechen, da das Objekt keine verschachtelten Eigenschaften hat und wir in der Regel über Tiefkopieren im Kontext der Veränderung verschachtelter Eigenschaften sprechen.
In JavaScript erzeugen Standardmethoden zum Kopieren von Objekten (Spread-Syntax, Array.prototype.concat()
, Array.prototype.slice()
, Array.from()
und Object.assign()
) keine Tiefkopien (stattdessen erstellen sie Flachkopien).
Eine Möglichkeit, eine Tiefkopie eines JavaScript-Objekts zu erstellen, wenn es serialisiert werden kann, ist die Verwendung von JSON.stringify()
, um das Objekt in einen JSON-String zu konvertieren, und dann JSON.parse()
, um den String zurück in ein (vollständig neues) JavaScript-Objekt zu konvertieren:
const ingredientsList = ["noodles", { list: ["eggs", "flour", "water"] }];
const ingredientsListDeepCopy = JSON.parse(JSON.stringify(ingredientsList));
Da eine Tiefkopie keine Referenzen zu ihrem Quellobjekt teilt, wirken sich Änderungen an der Tiefkopie nicht auf das Quellobjekt aus.
// Change the value of the 'list' property in ingredientsListDeepCopy.
ingredientsListDeepCopy[1].list = ["rice flour", "water"];
// The 'list' property does not change in ingredients_list.
console.log(ingredientsList[1].list);
// Array(3) [ "eggs", "flour", "water" ]
Das im obigen Code gezeigte Objekt ist jedoch einfach genug, um serialisierbar zu sein. Viele JavaScript-Objekte sind jedoch nicht serialisierbar — zum Beispiel Funktionen (mit Closures), Symbole, Objekte, die HTML-Elemente in der HTML DOM API darstellen, rekursive Daten und viele andere Fälle. Der Aufruf von JSON.stringify()
, um die Objekte in diesen Fällen zu serialisieren, wird fehlschlagen. Es gibt daher keine Möglichkeit, Tiefkopien solcher Objekte zu erstellen.
Die Web-API structuredClone()
erstellt ebenfalls Tiefkopien und bietet den Vorteil, dass übertragbare Objekte in der Quelle an die neue Kopie übertragen werden können, anstatt nur kopiert zu werden. Sie unterstützt auch mehr Datentypen, wie z.B. Error
. Beachten Sie jedoch, dass structuredClone()
keine Funktion der JavaScript-Sprache selbst ist — es ist eine Funktion von Browsern und anderen JavaScript-Hosts, die Web-APIs implementieren. Und der Aufruf von structuredClone()
, um ein nicht serialisierbares Objekt zu klonen, wird auf die gleiche Weise fehlschlagen wie der Aufruf von JSON.stringify()
zur Serialisierung.
Siehe auch
- Verwandte Glossarbegriffe:
Window.structuredClone()
WorkerGlobalScope.structuredClone()