Einige Fallstricke beim JavaScript Deep Copy

Einige Fallstricke beim JavaScript Deep Copy

Vorwort

Als ich zuvor zu einem Vorstellungsgespräch in einer Firma ging, stellte mir der Interviewer eine Frage: „Wie kann ich ein Objekt vollständig kopieren?“ Damals war ich insgeheim entzückt. Ist es notwendig, über eine so einfache Frage nachzudenken? Also platzte es aus mir heraus: „Es gibt zwei häufig verwendete Methoden. Die erste besteht darin, JSON.parse(JSON.stringify(obj)) zu verwenden, und die zweite darin, for...in plus Rekursion zu verwenden.“ Nachdem er dies angehört hatte, nickte der Interviewer und war ziemlich zufrieden.
Dieses Problem hat mich damals nicht besonders gestört, bis ich vor einiger Zeit noch einmal darüber nachdachte und feststellte, dass beide oben genannten Methoden Fehler enthielten.

Eine Frage stellen

Was ist also der oben erwähnte Fehler?

Spezielle Objektkopie

Stellen wir uns zunächst ein Objekt vor, das die folgenden Mitglieder hat, ohne gängige Typen zu berücksichtigen:

const obj = {
    arr: [111, 222],
    obj: {Schlüssel: 'Objekt'},
    a: () => {console.log('Funktion')},
    Datum: neues Datum(),
    reg: /regulär/ig
}

Dann kopieren wir es einmal mit den beiden oben genannten Methoden.

JSON-Methode

JSON.parse(JSON.stringify(obj))

Ausgabe:

Es ist ersichtlich, dass sowohl die normalen Objekte als auch die Arrays in obj kopiert werden können, aber das Datumsobjekt wird zu einer Zeichenfolge, die Funktion verschwindet direkt und der reguläre Ausdruck wird zu einem leeren Objekt.
Schauen wir uns die for...in-Methode mit Rekursion an

Rekursion

Funktion istObj(obj) {
    return (Typ von Objekt === 'Objekt' || Typ von Objekt === 'Funktion') && Objekt !== null
}
Funktion deepCopy(Objekt) {
    Lassen Sie tempObj = Array.isArray(obj) ? [] : {}
    für (let key in obj) {
        tempObj[Schlüssel] = isObj(obj[Schlüssel]) ? deepCopy(obj[Schlüssel]) : obj[Schlüssel]
    }
    gibt tempObj zurück
}

Ergebnis:

abschließend

Aus dem obigen Test können wir ersehen, dass diese beiden Methoden keine Objekte vom Typ „Funktion“, „Datum“ und „Registrierung“ kopieren können.

  • Ring

Was ist ein Ring?

Eine Schleife ist ein zirkulärer Verweis zwischen Objekten, der eine geschlossene Schleife ergibt. Zum Beispiel das folgende Objekt:

var a = {}

aa = ein

Bei Verwendung der beiden oben genannten Methoden zum Kopieren wird direkt ein Fehler gemeldet

Lösung

  • Ring

Sie können eine WeakMap-Struktur verwenden, um kopierte Objekte zu speichern. Jedes Mal, wenn Sie ein Objekt kopieren, fragen Sie die WeakMap ab, um zu sehen, ob das Objekt kopiert wurde. Wenn es kopiert wurde, nehmen Sie das Objekt heraus und geben es zurück. Transformieren Sie die Funktion deepCopy in Folgendes

Funktion deepCopy(obj, hash = neue WeakMap()) {
    wenn (hash.has(obj)) returniere hash.get(obj)
    lass cloneObj = Array.isArray(obj) ? [] : {}
    hash.set(Objekt, Klonobjekt)
    für (let key in obj) {
        cloneObj[Schlüssel] = isObj(obj[Schlüssel]) ? deepCopy(obj[Schlüssel], hash) : obj[Schlüssel];
    }
    returniere Klonobjekt
}

Ring kopieren Ergebnis:

Kopieren von Sonderobjekten

Die Lösung dieses Problems ist ziemlich kompliziert, da es zu viele Objekttypen gibt, die speziell behandelt werden müssen. Daher habe ich auf die strukturierte Kopie auf MDN verwiesen und sie dann mit der Lösung für den Ring kombiniert:

// Löse nur Datums- und Registrierungstypen, andere kannst du selbst hinzufügen function deepCopy(obj, hash = new WeakMap()) {
    lass cloneObj
    let Konstruktor = obj.konstruktor
    Schalter(Konstruktor){
        Fall RegExp:
            cloneObj = neuer Konstruktor(obj)
            brechen
        Falldatum:
            cloneObj = neuer Konstruktor(obj.getTime())
            brechen
        Standard:
            wenn (hash.has(obj)) returniere hash.get(obj)
            cloneObj = neuer Konstruktor()
            hash.set(Objekt, Klonobjekt)
    }
    für (let key in obj) {
        cloneObj[Schlüssel] = isObj(obj[Schlüssel]) ? deepCopy(obj[Schlüssel], hash) : obj[Schlüssel];
    }
    returniere Klonobjekt
}

Kopierergebnis:

Die Vollversion finden Sie unter lodash deep copy

  • Kopie der Funktion

Die strukturierte Kopie auf MDN löst jedoch immer noch nicht das Problem des Funktionskopierens.

Bisher habe ich nur daran gedacht, die Funktion mit der eval-Methode zu kopieren, aber diese Methode funktioniert nur für Pfeilfunktionen. Wenn sie die Form fun(){} hat, schlägt sie fehl.

Funktion kopieren, um Funktionstyp hinzuzufügen

Ergebnis kopieren

Fehlertyp

Nachtrag

Das Deep Copy von JavaScript weist noch weitere Probleme auf als die oben genannten. Ein weiteres Problem ist, wie die Eigenschaften in der Prototypenkette kopiert werden. Wie kopiere ich nicht aufzählbare Eigenschaften? Wie kopiere ich Fehlerobjekte usw.? Darauf werde ich hier nicht näher eingehen.

Es wird jedoch weiterhin empfohlen, im täglichen Leben die JSON-Methode zu verwenden. Diese Methode deckt die meisten Geschäftsanforderungen ab, sodass einfache Dinge nicht komplizierter werden müssen. Wenn Sie jedoch während des Interviews auf einen Interviewer treffen, der kleinlich ist, wird Ihre Antwort auf diese Frage ihn definitiv gut dastehen lassen.

Damit ist dieser Artikel über einige Fallstricke von JavaScript Deep Copy abgeschlossen. Weitere relevante Inhalte zu JavaScript Deep Copy finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Eine kurze Diskussion über Shallow Copy und Deep 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)
  • Detaillierte Erklärung von JS Deep Copy und Shallow Copy
  • Lassen Sie sich die tiefe Kopie von js verstehen

<<:  Implementierung eines Crawler-Scrapy-Image, das von Dockerfile basierend auf Alpine erstellt wurde

>>:  Installation und Verwendung der MySQL MyCat-Middleware

Artikel empfehlen

Beispielcode zur Implementierung des Verlaufs in Vuex

Ich habe vor Kurzem eine visuelle Operationsplatt...

Detaillierte Erklärung des JS-Browserspeichers

Inhaltsverzeichnis Einführung Plätzchen Was sind ...

Vues Render-Funktion

Inhaltsverzeichnis 1. Knoten, Bäume und virtuelle...

Galeriefunktion durch natives Js implementiert

Inhaltsverzeichnis Der erste Der Zweite Native Js...

So aktivieren Sie TLS- und CA-Authentifizierung in Docker

Inhaltsverzeichnis 1. Zertifikat generieren 2. Ak...

Vue implementiert eine einfache Slider-Verifizierung

Dieses Artikelbeispiel zeigt die Implementierung ...

JavaScript zum Erreichen eines dynamischen Farbwechsels der Tabelle

In diesem Artikel wird der spezifische Code für J...

Detaillierte Erklärung der verschiedenen Verwendungen von proxy_pass in nginx

Inhaltsverzeichnis Proxy-Weiterleitungsregeln Der...

Detaillierte Erklärung zur Verwendung von MySQL Online DDL

Inhaltsverzeichnis Text LOCK-Parameter ALGORITHMU...

SSH-Schlüsselpaare von einer oder mehreren Linux-Instanzen trennen

Schlüsselpaar trennen Trennen Sie SSH-Schlüsselpa...