Eine kurze Diskussion über Shallow Copy und Deep Copy in JavaScript

Eine kurze Diskussion über Shallow Copy und Deep Copy in JavaScript

Im Internet gibt es viele Diskussionen zu diesem Thema. Ich habe sie je nach Situation selbst sortiert. Am Ende konnte ich eine nahezu perfekte Deep Copy erstellen. Jeder ist herzlich eingeladen, mitzudiskutieren.

Objekte in javascript sind Referenztypen. Beim Kopieren von Objekten müssen Sie überlegen, ob Sie Shallow Copy oder Deep Copy verwenden möchten.

1. Direkte Zuordnung

Ein Objekt ist ein Referenztyp. Wird es direkt einem anderen Objekt zugewiesen, handelt es sich lediglich um eine Referenz. Tatsächlich verweisen die beiden Variablen auf dasselbe Datenobjekt. Ändern sich die Eigenschaften eines Objekts, ändern sich auch die Eigenschaften des anderen.

Beispiel 1, einfaches Beispiel:

lass Mensch1 = {
    ID: 1,
    Name: "glücklich"
};
human2 = human1; // Hier ist eine direkte Zuweisung console.log(human1); // {id: 1, name: 'happy'}
console.log(human2); // {id: 1, name: "glücklich"}
 
// Wenn der Name von human1 geändert wird, wird auch der von human2 geändert human1.name = "life";
console.log(Mensch1); // {id: 1, name: 'Leben'}
console.log(human2); // {id: 1, name: 'leben'}

Beispiel 2: Durch die Übergabe eines Objekts als Parameter wird auch eine Referenz übergeben:

lass Mensch1 = {
    ID: 1,
    Name: "glücklich"
};
 
console.log(Mensch1); // {id: 1, name: "glücklich"}
 
Funktion foo(Mensch) {
    // Hier wird der Name des menschlichen Objektes geändert human.name = "life";
}
foo(human1); // die Übergabe eines Objekts erfolgt per Referenz console.log(human1); // {id: 1, name: 'life'}

2. Oberflächliche Kopie

Bei einer oberflächlichen Kopie wird nur die erste Ebene des Objekts kopiert. Wenn der Eigenschaftswert der ersten Ebene ein Objekt ist, wird nur ein Verweis auf die Eigenschaft kopiert.

lass Objekt1 = {
    ein: 1,
    b: { // b ist ein Objekt b1: 2
    }
};
object2 = Object.assign({}, object1); // Dies ist eine oberflächliche Kopie, bei der nur die Referenz von Objekt b kopiert wird // a ist ein regulärer Typ und beeinflusst sich nicht gegenseitig object1.a = 10;
konsole.log(objekt1.a); // 10
konsole.log(Objekt2.a); // 1
 
// b ist ein Objekt, das sich gegenseitig beeinflusst object1.b.b1 = 20;
konsole.log(objekt1.b.b1); // 20
konsole.log(objekt2.b.b1); // 20


Wenn Sie eine vollständige Kopie erreichen möchten, müssen Sie eine tiefe Kopie verwenden.

3. Tiefe Kopie

Sen-Kopie bedeutet, dass nicht nur eine Ebene kopiert werden muss, sondern auch die darin enthaltenen Ebenen (sofern es sich um Objekte handelt) kopiert werden müssen.

1. JSON-Objektmethode

Wenn bestätigt werden kann, dass es sich bei dem Objekt um ein JSON Objekt handelt, kann es im JSON Objektformat verwendet werden.

Verwenden Sie das obige Beispiel:

lass Objekt1 = {
    ein: 1,
    b: { // b ist ein Objekt b1: 2
    }
};
 
object2 = JSON.parse(JSON.stringify(object1)); // Tiefe Kopie // a ist ein regulärer Typ und beeinflusst sich nicht gegenseitig object1.a = 10;
konsole.log(objekt1.a); // 10
konsole.log(objekt2.a); // 1
 
// b ist ein Objekt und beeinflusst sich nicht gegenseitig object1.b.b1 = 20;
konsole.log(objekt1.b.b1); // 20
konsole.log(Objekt2.b.b1); // 2


Das Prinzip der tiefen Kopie besteht hier eigentlich darin, das Objekt zuerst in eine json Zeichenfolge und dann in json Objekt umzuwandeln. Nach der Umwandlung in eine json Zeichenfolge hat es nichts mehr mit dem ursprünglichen Objekt zu tun.

Vorteile dieser Methode: Sie ist sehr einfach umzusetzen.

Mangel:

Wenn ein Attributwert eine Funktion ist, kann er nicht kopiert werden und die Daten gehen verloren.
Darüber hinaus können Prototypobjekte nicht kopiert werden.

Daher ist diese Methode nur für Objekte geeignet, bei denen bestätigt ist, dass es sich um reine json -Daten handelt.

2. Rekursives Kopieren

Da wir Schicht für Schicht kopieren müssen, ist es einfach, über einen rekursiven Ansatz nachzudenken. Siehe die folgende Implementierung:

Funktion deepCopy(Quelle) {
    // Wenn es kein Objekt oder null ist, direkt zurückgeben, if (typeof source !== 'object' || source === null) {
        Rücklaufquelle;
    }
 
    lass Ziel = {};
    // Eigenschaften durchlaufen und kopieren für (let k in source) {
        wenn (!source.hasOwnProperty(k)) {
            weitermachen;
        }
 
        if (typeof source[k] === 'object') { // Wenn es ein Objekt ist, rekursiv kopieren target[k] = deepCopy(source[k]);
            weitermachen;
        }
 
        let descriptor = Object.getOwnPropertyDescriptor(Quelle, k);
        Objekt.defineProperty(Ziel, k, Deskriptor);
    }
 
    Rücklaufziel;
}

Da die Objekte Schicht für Schicht kopiert werden, beeinflussen sich die beiden Objekte nach Abschluss des Kopiervorgangs nicht gegenseitig und Methoden können auch unterstützt werden.

lass Objekt1 = {
    ein: 1,
    b: { // b ist ein Objekt b1: 2
    },
    f: function() { // f ist eine Methode console.log(3);
    }
};
object2 = deepCopy(object1); // Deep Copy, Sie können auch Funktionen kopieren.
objekt1.f(); // 3
objekt2.f(); // 3
 
// b ist ein Objekt und beeinflusst sich nicht gegenseitig object1.b.b1 = 20;
konsole.log(objekt1.b.b1); // 20
konsole.log(Objekt2.b.b1); // 2


Prototypobjekte kopieren

Bei dieser Methode gibt es jedoch immer noch ein Problem, nämlich, dass das Prototypobjekt nicht kopiert werden kann. Lassen Sie es uns ein wenig verbessern:

// Ändern Sie let target = {}; wie folgt // um sicherzustellen, dass der Prototyp auch kopiert wird let target = Object.create(Object.getPrototypeOf(source));


Das ist alles. Lassen Sie es uns anhand eines Beispiels überprüfen:

Funktion Mensch() {
    diese.id = 1;
}
Mensch.prototype.bar = Funktion() {
    console.log("Leiste");
};
 
let Mensch1 = neuer Mensch();
Mensch2 = tiefe Kopie (Mensch1);
 
konsole.log("Mensch1", Mensch1);
Konsole.log("Mensch2", Mensch2);


Schauen Sie sich die Prototypen der nächsten beiden Objekte an:

Vollständige Kopie des Prototypobjekts:

Perfekte Kopie.

Natürlich gibt es bei dieser Methode ein Problem: Wenn die Rekursionsebene zu tief ist, kann es leicht zu einem Stapelüberlauf kommen. Allerdings empfiehlt es sich in der Praxis auch, sehr große Objekte nicht zu kopieren, hier gibt es sicher auch andere gute Lösungen.

Dies ist das Ende dieses Artikels über Shallow Copy und Deep Copy JavaScript . Weitere relevante Inhalte zu Shallow Copy und Deep Copy in JavaScript finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Referenzdokumente:

JS implementiert Deep Copy: https://www.cnblogs.com/dobeco/p/11295316.html
Object.assign(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Objekt.erstellen(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/erstellen
Object.getPrototypeOf(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf
Object.defineProperty(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.getOwnPropertyDescriptor(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor
hasOwnProperty(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

Das könnte Sie auch interessieren:
  • Detaillierte Erklärung von Deep Copy und Shallow Copy in JavaScript
  • Detaillierte Beschreibung von Shallow Copy und Deep Copy in js
  • Detaillierte Erläuterung der Deep Copy und Shallow Copy im JS-Variablenspeicher
  • Kopieren von JS-Objekten (Deep Copy und Shallow Copy)
  • Alltägliche Diskussionen über Deep Copy und Shallow Copy in JavaScript

<<:  MySQL Infobright-Installationsschritte

>>:  Fünf Lösungen für Cross-Browser-Probleme (Zusammenfassung)

Artikel empfehlen

Zwei Methoden zum Strecken des Hintergrundbilds einer Webseite

Es gibt zwei Lösungen: Eine Möglichkeit ist CSS, b...

Rendering-Funktion und JSX-Details

Inhaltsverzeichnis 1. Grundlagen 2. Knoten, Bäume...

Tomcat verwendet Thread-Pool zur Verarbeitung gleichzeitiger Remote-Anfragen

Wenn wir verstehen, wie Tomcat gleichzeitige Anfr...

RHEL7.5 MySQL 8.0.11 Installations-Tutorial

Dieser Artikel zeichnet das Installationstutorial...

Beispiel für den Aufbau eines Redis-Sentinel-Clusters basierend auf Docker

1. Übersicht Redis Cluster ermöglicht hohe Verfüg...

Detaillierte Erklärung, wann Javascript-Skripte ausgeführt werden

JavaScript-Skripte können überall in HTML eingebe...

Vue implementiert die Benutzeranmeldungsumschaltung

In diesem Artikelbeispiel wird der spezifische Co...

Methoden und Probleme bei der Installation von MariaDB in CentOS unter MySQL

Löschen Sie die zuvor installierte MariaDB 1. Ver...