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

MySQL berechnet die Anzahl der Tage, Monate und Jahre zwischen zwei Daten

Die in MySQL integrierte Datumsfunktion TIMESTAMP...

Vue implementiert Chat-Schnittstelle

In diesem Artikelbeispiel wird der spezifische Co...

So entfernen Sie „Enter“, „Senden“ und „Enter != Senden“ aus dem Formular

Um das Problem „Eingeben != Absenden“ zu implement...

Mehrere wichtige MySQL-Variablen

Es gibt viele MySQL-Variablen, von denen einige u...

Analyse und Beschreibung von Netzwerkkonfigurationsdateien unter Ubuntu-System

Ich bin heute auf ein seltsames Netzwerkproblem g...

JavaScript implementiert einfaches Scrollfenster

In diesem Artikelbeispiel wird der spezifische Ja...

Vue implementiert einen einfachen Bildwechseleffekt

In diesem Artikelbeispiel wird der spezifische Co...

js-Methode zum Löschen eines Felds in einem Objekt

Dieser Artikel stellt hauptsächlich die Implement...

Zusammenfassung zur Anwendung dekorativer Elemente im Webdesign

<br />Vorwort: Bevor Sie dieses Tutorial les...

js, um den Zahlungs-Countdown zu realisieren und zur Startseite zurückzukehren

Zahlungs-Countdown, um zur Startseite zurückzukeh...

Detaillierte Erklärung inkompatibler Änderungen von Komponenten in vue3

Inhaltsverzeichnis Funktionale Komponenten So sch...

js behandelt die Kontoabmeldung beim Schließen des Browsers

Inhaltsverzeichnis Klassischer Ansatz Frage Weite...