Detaillierte Erläuterung der Deep Copy und Shallow Copy im JS-Variablenspeicher

Detaillierte Erläuterung der Deep Copy und Shallow Copy im JS-Variablenspeicher

Variabler Typ und Speicherplatz

Stapelspeicher und Heap-Speicher

Grundlegende Datentypen

Zeichenfolge, Zahl, Null, undefiniert, Boolesch, Symbol (neu in ES6) Variablenwerte werden im Stapelspeicher gespeichert, und die Werte von Variablen können direkt abgerufen und geändert werden. Grundlegende Datentypen haben keine Kopien, beispielsweise können Sie den Wert von 1 nicht ändern.

Referenztypen

Objekt Funktion RegExp Math Date Der Wert ist ein Objekt, welches im Heap-Speicher abgelegt wird. Die Variable im Stack-Speicher speichert einen Zeiger auf die entsprechende Adresse im Heap-Speicher.
Beim Zugriff auf einen Referenztyp müssen Sie zuerst den Adresszeiger des Objekts vom Stapel nehmen und dann die erforderlichen Daten aus dem Heap-Speicher abrufen.

Grafischer Speicherplatz

let a1 = 0; // Stapelspeicher let a2 = "this is string" // Stapelspeicher let a3 = null; // Stapelspeicher let b = { x: 10 }; // Variable b existiert im Stapel, { x: 10 } existiert als Objekt im Heap let c = [1, 2, 3]; // Variable c existiert im Stapel, [1, 2, 3] existiert als Objekt im Heap 

Zuordnung von Verweistypen

sei a = { x: 10, y: 20 }
sei b = a;
bx = 5;
konsole.log(ax); // 5 

Tiefe Kopie und flache Kopie

Tiefes Kopieren

Kopieren Sie ein Objekt vollständig aus dem Speicher, öffnen Sie einen neuen Bereich im Heap-Speicher, um das neue Objekt zu speichern, und ändern Sie das neue Objekt. Dies hat keine Auswirkungen auf das ursprüngliche Objekt.

Flache Kopie

Eine oberflächliche Kopie ist eine bitweise Kopie eines Objekts, die ein neues Objekt mit einer exakten Kopie der Eigenschaftswerte des Originalobjekts erstellt. Wenn das Attribut ein primitiver Typ ist, wird der Wert des primitiven Typs kopiert; wenn das Attribut eine Speicheradresse (Referenztyp) ist, wird die Speicheradresse kopiert.

Zuordnung von Objekten

Wenn wir einer neuen Variablen ein Objekt zuweisen, wird tatsächlich die Adresse des Objekts im Stapel zugewiesen, nicht die Daten im Heap. Das heißt, die beiden Objekte verweisen auf denselben Speicherplatz. Unabhängig davon, welches Objekt sich ändert, ändert sich tatsächlich der Inhalt des Speicherplatzes. Daher sind die beiden Objekte verknüpft.

Vergleich der drei

Fünf gängige Methoden des Shallow Copy

Objekt.zuweisen()

Die Methode Object.assign() kann eine beliebige Anzahl aufzählbarer Eigenschaften des Quellobjekts in das Zielobjekt kopieren und dann das Zielobjekt zurückgeben. Aber Object.assign() führt eine oberflächliche Kopie durch

Object.assign durchläuft alle Eigenschaften des Quellobjekts (Quellen) von links nach rechts und weist sie dann mit = dem Zielobjekt (Ziel) zu.

var obj = { a: {a: "kobe", b: 39},b:1 };
        var initialObj = Object.assign({}, obj);
        initialObj.aa = "waten";
        initialObj.b = 2;
        console.log(obj.aa); //waten
        console.log(obj.b); //1

Spread-Operator

sei obj = {a:1,b:{c:1}}
sei obj2 = {...obj};
Objekt.a=2;
console.log(obj); //{a:2,b:{c:1}}
console.log(obj2); //{a:1,b:{c:1}}

obj.bc = 2;
console.log(obj); //{a:2,b:{c:2}}
console.log(obj2); //{a:1,b:{c:2}}

Array.Prototyp.Scheibe

Die Methode slice() gibt ein neues Array-Objekt zurück, das eine oberflächliche Kopie des durch begin und end (ohne end) bestimmten Original-Arrays ist. Der Basistyp des ursprünglichen Arrays wird nicht geändert, aber der Referenztyp wird geändert.

sei arr = [1, 3, {
    Benutzername: „kobe“
    }];
lass arr3 = arr.slice();
arr3[0]=0;
arr3[2].Benutzername = "wade"
Konsole.log(arr);

Array.prototype.concat()

sei arr = [1, 3, {
    Benutzername: „kobe“
    }];
lass arr2=arr.concat();   
arr3[0]=0;
arr2[2].Benutzername = "wade";
Konsole.log(arr);

Handschriftliche oberflächliche Kopie

Funktion flacheKopie(Quelle) {
    var dst = {};
    für (var prop in src) {
        wenn (src.hasOwnProperty(prop)) {
            dst[Eigenschaft] = src[Eigenschaft];
        }
    }
    Rückgabeziel;
}

Gängige Methoden für Deep Copy

jsON.parse(jsON.stringify())

Bei der Implementierung von Deep Copy über JSON.stringify sind einige Dinge zu beachten

Wenn der Wert des kopierten Objekts eine Funktion, ein undefiniertes Element oder ein Symbol enthält, verschwindet das Schlüssel-Wert-Paar in der von JSON.stringify() serialisierten JSON-Zeichenfolge.

Nicht aufzählbare Eigenschaften können nicht kopiert werden. Die Prototypenkette des Objekts kann nicht kopiert werden.

Durch Kopieren des Datumsreferenztyps wird eine Zeichenfolge erstellt

Das Kopieren eines RegExp-Referenztyps führt zu einem leeren Objekt

Wenn das Objekt NaN, Infinity und -Infinity enthält, wird das serialisierte Ergebnis null

Objekte können nicht in einer Schleife kopiert werden (z. B. obj[key] = obj)

sei arr = [1, 3, {
    Benutzername: „kobe“
}];
Lassen Sie arr4 = JSON.parse(JSON.stringify(arr));
arr4[2].Benutzername = "duncan"; 
konsole.log(arr, arr4)

Handgeschriebene Beggar's Edition Deep Copy

Zunächst einmal kann diese DeepClone-Funktion keine nicht aufzählbaren Eigenschaften und Symboltypen kopieren.

Hier wird die Schleifeniteration nur für den Wert des Objektreferenztyps durchgeführt und die Array-, Datums-, RegExp-, Fehler- und Funktionsreferenztypen können nicht korrekt kopiert werden.

Objekte werden geloopt, d.h. zirkuläre Referenzen (z.B. obj1.a = obj)

Funktion Klon(Ziel) {
    wenn (Typ des Ziels === 'Objekt') {
        Lassen Sie cloneTarget = Array.isArray(target) ? [] : {};
        für (const key in target) {
            cloneTarget[Schlüssel] = Klon(Ziel[Schlüssel]);
        }
        gibt Klonziel zurück;
    } anders {
        Rücklaufziel;
    }
};

Kaiser Edition - Vollständige Kopie

Dieses Beispiel stammt von ConardLis GitHub, Quelladresse: https://github.com/ConardLi/

const mapTag = "[Objektzuordnung]";
    const setTag = "[Objektsatz]";
    const arrayTag = "[Objekt-Array]";
    const objectTag = "[Objekt Objekt]";
    const argsTag = "[Objektargumente]";

    const boolTag = "[Objekt Boolean]";
    const dateTag = "[Objekt Datum]";
    const numberTag = "[Objektnummer]";
    const stringTag = "[Objekt String]";
    const symbolTag = "[Objekt Symbol]";
    const errorTag = "[Objektfehler]";
    const regexpTag = "[Objekt RegExp]";
    const funcTag = "[Objektfunktion]";

    const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];

    Funktion fürJeden(Array, Iteratee) {
      lass Index = -1;
      const Länge = Array.Länge;
      während (++Index < Länge) {
        iterieren(Array[Index], Index);
      }
      Array zurückgeben;
    }

    Funktion istObjekt(Ziel) {
      const Typ = Typ des Ziels;
      Rückgabeziel !== null && (Typ === "Objekt" || Typ === "Funktion");
    }

    Funktion getType(Ziel) {
      gibt Object.prototype.toString.call(Ziel) zurück;
    }

    Funktion getInit(Ziel) {
      const Ctor = Ziel.Konstruktor;
      gib neuen Ctor() zurück;
    }

    Funktion KlonSymbol(Ziel) {
      gibt Objekt zurück (Symbol.prototype.valueOf.call(target));
    }

    Funktion cloneReg(Ziel) {
      const reFlags = /\w*$/;
      const Ergebnis = neuer Zielkonstruktor (Ziel.Quelle, reFlags.exec (Ziel));
      Ergebnis.letzterIndex = Ziel.letzterIndex;
      Ergebnis zurückgeben;
    }

    Funktion Klonfunktion(func) {
      const bodyReg = /(?<={)(.|\n)+(?=})/m;
      const paramReg = /(?<=\().+(?=\)\s+{)/;
      const funcString = func.toString();
      wenn (Funktion.Prototyp) {
        const param = paramReg.exec(funcString);
        const body = bodyReg.exec(funcString);
        wenn (Körper) {
          wenn (Param) {
            const paramArr = param[0].split(",");
            gib eine neue Funktion zurück (...paramArr, body[0]);
          } anders {
            gib eine neue Funktion zurück (Body[0]);
          }
        } anders {
          gibt null zurück;
        }
      } anders {
        gibt eval(Funktionsstring) zurück;
      }
    }

    Funktion cloneOtherType(Ziel, Typ) {
      const Ctor = Ziel.Konstruktor;
      Schalter (Typ) {
        Fall boolTag:
        FallnummerTag:
        Fall-StringTag:
        FallfehlerTag:
        FalldatumTag:
          gib neuen Ctor(Ziel) zurück;
        Fall RegexpTag:
          returniere cloneReg(Ziel);
        FallsymbolTag:
          gibt KlonSymbol(Ziel) zurück;
        Fall-FunktionsTag:
          gibt Klonfunktion (Ziel) zurück;
        Standard:
          gibt null zurück;
      }
    }

    Funktion Klon(Ziel, Karte = neue WeakMap()) {
      // Den Originaltyp klonen if (!isObject(target)) {
        Rücklaufziel;
      }

      // Initialisieren const type = getType(target);
      lass Ziel klonen;
      wenn (deepTag.includes(Typ)) {
        cloneTarget = getInit(Ziel, Typ);
      } anders {
        returniere cloneOtherType(Ziel, Typ);
      }

      // Zirkelreferenzen vermeiden if (map.get(target)) {
        Karte zurückgeben.get(Ziel);
      }
      map.set(Ziel, Klonziel);

      // Klonen Sie das Set
      wenn (Typ === setzeTag) {
        ziel.fürJeden(Wert => {
          cloneTarget.add(Klon(Wert, Karte));
        });
        gibt Klonziel zurück;
      }

      // Die Karte klonen
      wenn (Typ === MapTag) {
        target.forEach((Wert, Schlüssel) => {
          cloneTarget.set(Schlüssel, Klon(Wert, Map));
        });
        gibt Klonziel zurück;
      }

      // Objekte und Arrays klonen const keys = Typ === ArrayTag ? undefiniert : Object.keys(Ziel);
      fürJeden(Schlüssel || Ziel, (Wert, Schlüssel) => {
        wenn (Schlüssel) {
          Schlüssel = Wert;
        }
        cloneTarget[Schlüssel] = Klon(Ziel[Schlüssel], Map);
      });

      gibt Klonziel zurück;
    }

    const map = neue Map();
    map.set("Schlüssel", "Wert");
    map.set("ConardLi", "Code Geheimer Garten");

    const set = neues Set();
    setze.add("ConardLi");
    set.add("Code geheimer Garten");

    const Ziel = {
      Feld1: 1,
      Feld2: undefiniert,
      Feld3: {
        Kind: "Kind"
      },
      Feld4: [2, 4, 8],
      leer: null,
      Karte,
      Satz,
      bool: neuer Boolean(true),
      num: neue Zahl(2),
      str: neuer String(2),
      Symbol: Objekt(Symbol(1)),
      Datum: neues Datum(),
      reg: /\d+/,
      Fehler: neuer Fehler(),
      func1: () => {
        console.log("Code geheimer Garten");
      },
      func2: Funktion(a, b) {
        gib a + b zurück;
      }
    };

    const Ergebnis = Klon(Ziel);

    konsole.log(Ziel);
    console.log(Ergebnis);

Oben finden Sie eine ausführliche Erläuterung zu Deep Copy und Shallow Copy von JS-Variablenspeicher. Weitere Informationen zu Deep Copy und Shallow Copy von JS-Variablenspeicher finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM!

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

<<:  18 allgemeine Befehle in der MySQL-Befehlszeile

>>:  Detaillierte Erläuterung verschiedener Kommunikationswege zwischen Linux-Benutzerstatus und Kernelstatus

Artikel empfehlen

Vue+Openlayer verwendet modify, um den gesamten Code des Elements zu ändern

Vue+Openlayer verwendet „modify“, um Elemente zu ...

So erstellen Sie eine Ansicht für mehrere Tabellen in MySQL

Erstellen Sie in MySQL eine Ansicht für zwei oder...

Eine vollständige Liste gängiger Linux-Systembefehle für Anfänger

Das Erlernen von Linux-Befehlen stellt für die me...

Über die Überlappung von Randwert und vertikalem Rand in CSS

Rand paralleler Boxen (Überlappung doppelter Ränd...

MP3- oder Flashplayer-Code auf der Webseite abspielen

Code kopieren Der Code lautet wie folgt: <Obje...

Erläuterung der Schritte für Tomcat zur Unterstützung des https-Zugriffs

So ermöglichen Sie Tomcat die Unterstützung des h...

Einführung in die Verwendung von exists und except in SQL Server

Inhaltsverzeichnis 1. existiert 1.1 Beschreibung ...

Vue + Express + Socket realisiert Chat-Funktion

In diesem Artikel wird der spezifische Code von V...

MySQL sql_mode-Analyse und Einstellungserklärung

Beim Einfügen eines Datensatzes in die MySQL-Date...

So beschränken Sie das Eingabefeld in HTML auf die Eingabe reiner Zahlen

Beschränken Sie input Eingabefeld auf reine Zahle...