Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

Tiefenkopie

Eine Tiefenkopie eines Objekts ist eine Kopie, deren Eigenschaften nicht dieselben Referenzen teilen (auf dieselben zugrunde liegenden Werte verweisen) wie die des Ursprungsobjekts, von dem die Kopie erstellt wurde. Daher können Sie sicher sein, dass bei Änderungen entweder am Quellobjekt oder an der Kopie nicht das andere Objekt ebenfalls geändert wird. Dieses Verhalten steht im Gegensatz zu dem einer Flachkopie, bei der Änderungen an geschachtelten Eigenschaften im Quellobjekt oder in der Kopie dazu führen können, dass sich das andere Objekt ebenfalls ändert.

Das Tiefenkopieren wird normalerweise rekursiv wie folgt implementiert:

  1. Ein neues Objekt desselben Typs wird erstellt. Die Prototypenkette wird möglicherweise kopiert (meistens jedoch nicht), aber beispielsweise sollte das Tiefenkopieren eines Array in einem Array und nichts anderem resultieren.
  2. Für jede eigene Eigenschaft des ursprünglichen Objekts wird eine Eigenschaft mit demselben Schlüssel und denselben Deskriptoren im neuen Objekt definiert.
  3. Der Wert jeder neuen Eigenschaft wird auf eine Tiefenkopie des Werts der ursprünglichen Eigenschaft gesetzt. Wenn der Wert einer Eigenschaft ein primitiver Wert ist, wird keine Kopie angefertigt.
  4. Alle Daten, die nicht als Eigenschaften verfügbar sind (wie Map), werden tief kopiert, vorausgesetzt, die Implementierung erkennt den Objekttyp und weiß, wie die Daten abgerufen und gesetzt werden können.
  5. Normalerweise gibt es Unterstützung für zirkuläre Referenzen.

Da JavaScript keinen eingebauten Mechanismus hat, der eine echte Tiefenkopie durchführt, weichen Implementierungen in Bibliotheken häufig in technischen Details ab, zum Beispiel:

  • Ob nicht-auflistbare oder Symbol-Eigenschaften kopiert werden
  • Ob Zugriffseigenschaften als solche kopiert werden
  • Ob Prototyp-Eigenschaften kopiert werden
  • Welche Datenstrukturen das Kopieren von Daten außerhalb der Eigenschaften unterstützen

Eine Kopie eines Objekts, dessen Eigenschaften alle primitive Werte haben, entspricht sowohl der Definition einer Tiefenkopie als auch einer Flachkopie. Es ist jedoch wenig sinnvoll, in diesem Fall über die Tiefe einer solchen Kopie zu sprechen, da sie keine geschachtelten Eigenschaften hat und wir normalerweise im Kontext der Veränderung geschachtelter Eigenschaften über Tiefenkopien sprechen.

In JavaScript, die standardmäßigen eingebauten Objektkopieroperationen (Spread-Syntax, Array.prototype.concat(), Array.prototype.slice(), Array.from() und Object.assign()) erstellen keine Tiefenkopien (sie erstellen stattdessen Flachkopien).

Eine Möglichkeit, eine Tiefenkopie eines JavaScript-Objekts zu erstellen, sofern es serialisierbar ist, besteht darin, JSON.stringify() zu verwenden, um das Objekt in einen JSON-String zu konvertieren, und anschließend JSON.parse(), um den String zurück in ein (vollständig neues) JavaScript-Objekt zu konvertieren:

js
const ingredientsList = ["noodles", { list: ["eggs", "flour", "water"] }];
const ingredientsListDeepCopy = JSON.parse(JSON.stringify(ingredientsList));

Da eine Tiefenkopie keine Referenzen mit ihrem Ursprungsobjekt teilt, wirken sich Änderungen an der Tiefenkopie nicht auf das Ursprungsobjekt aus.

js
// 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" ]

Während das Objekt im obigen Code einfach genug ist, um serialisierbar zu sein, sind viele JavaScript-Objekte überhaupt nicht serialisierbar — zum Beispiel Funktionen (mit Closures), Symbole, Objekte, die HTML-Elemente in der HTML DOM API repräsentieren, rekursive Daten und viele andere Fälle. Das Aufrufen von JSON.stringify(), um die Objekte zu serialisieren, wird in solchen Fällen fehlschlagen. Das Tiefenkopieren dieser Objekte erfordert andere APIs oder Bibliotheken.

Die Web-API structuredClone() erstellt ebenfalls Tiefenkopien und bietet den Vorteil, dass übertragbare Objekte in der Quelle übertragen und nicht nur kopiert werden können. Sie kann auch mehr Datentypen verarbeiten, wie Error. Beachten Sie jedoch, dass structuredClone() kein Merkmal der JavaScript-Sprache selbst ist — vielmehr handelt es sich um ein Merkmal von Browsern und anderen JavaScript-Hosts, die Web-APIs implementieren. Und das Aufrufen von structuredClone() zum Klonen eines nicht serialisierbaren Objekts wird auf die gleiche Weise fehlschlagen wie das Aufrufen von JSON.stringify() zum Serialisieren.