Methodenbeispiel zum sicheren Abrufen tiefer Objekte von Object in Js

Methodenbeispiel zum sicheren Abrufen tiefer Objekte von Object in Js

Vorwort

Freunde, die am Frontend arbeiten, müssen auf Situationen gestoßen sein, in denen die vom Backend zurückgegebenen Daten in mehreren Schichten verschachtelt sind. Wenn ich den Wert eines tiefen Objekts abrufen möchte, führe ich Schicht für Schicht Nicht-Leer-Prüfungen durch, um Fehler zu vermeiden, beispielsweise:

const obj = {
    Waren:
        Name: "a",
     Schlagworte: {
            Name: 'Schnell',
         ID: 1,
         tagTyp: {
                Name: "Bezeichnung"
           }
       }
   }
}

Wenn ich tagType.name abrufen muss, lautet die Beurteilung wie folgt

wenn (obj.goods !== null
    && obj.goods.tags !== null
    && obj.goods.tags.tagType !== null) {
 
 }

Wenn der Attributname lang ist, ist der Code unlesbar.

Natürlich hat ECMAScript 2020 ?. eingeführt, um dieses Problem zu lösen:

let name = obj?.Waren?.Tags?.Tagestyp?.Name;

Aber wie geht man mit Browsern um, die nicht mit ES2020 kompatibel sind?

Text

Studenten, die Lodash verwendet haben, wissen möglicherweise, dass es in Lodash eine Get-Methode gibt. Auf der offiziellen Website heißt es:

_.get(Objekt, Pfad, [Standardwert])

Holen Sie sich den Wert entsprechend dem Pfad des Objekts. Wenn der aufgelöste Wert nicht definiert ist, wird er durch den Standardwert ersetzt.

Parameter

  1. Objekt (Objekt): Das abzurufende Objekt.
  2. Pfad (Array|Zeichenfolge): Der Pfad, aus dem die Eigenschaften abgerufen werden sollen.
  3. [Standardwert] ()*: Wenn der aufgelöste Wert nicht definiert ist, wird dieser Wert zurückgegeben.

Beispiel

var Objekt = { 'a': [{ 'b': { 'c': 3 } }] };
​
_.get(Objekt, 'a[0].b.c');
// => 3 
​
_.get(Objekt, ['a', '0', 'b', 'c']);
// => 3
​
_.get(Objekt, 'abc', 'Standard');
// => 'Standard'

Dies löst das Problem, aber (ich fürchte, es gibt ein „aber“)

Was passiert, wenn ich die Lodash-Bibliothek aus verschiedenen Gründen, beispielsweise aufgrund von Projekt- oder Unternehmensanforderungen, nicht verwenden kann?

Sehen wir uns nun an, wie lodash implementiert wird. Können wir nicht einfach den Code extrahieren? Dann können wir wieder fröhlich Steine ​​verschieben~~

Lodash-Implementierung:

Funktion get(Objekt, Pfad, Standardwert) {
  const Ergebnis = Objekt == null? undefiniert: baseGet(Objekt, Pfad)
  Rückgabeergebnis === undefiniert? Standardwert: Ergebnis
}

Was wir hier tun, ist sehr einfach. Schauen wir uns zuerst die Rückgabe an. Wenn das Objekt den Standardwert zurückgibt, befindet sich der Kerncode in baseGet. Schauen wir uns also die Implementierung von baseGet an.

Funktion baseGet(Objekt, Pfad) {
  //Konvertiere den Eingabestring path in ein Array,
  Pfad = castPath(Pfad, Objekt)
​
  lass Index = 0
  Konstante Länge = Pfadlänge
  // Durchlaufe das Array, um alle Objektebenen abzurufen while (object != null && index < length) {
    Objekt = Objekt[toKey(Pfad[index++])] // toKey-Methode}
  return (Index && Index == Länge)? Objekt: undefiniert
}
​

Hier verwenden wir zwei Funktionen: castPath (konvertiert den Eingabepfad in ein Array) und toKey (konvertiert den tatsächlichen Schlüssel).

Tokey-Funktion:

/** Wird als Referenz für verschiedene `Number`-Konstanten verwendet. */
Konstante UNENDLICHKEIT = 1 / 0
​
/**
 * Wandelt „Wert“ in einen String-Schlüssel um, wenn es sich nicht um einen String oder ein Symbol handelt.
 *
 * @Privat
 * @param {*} Wert Der zu prüfende Wert.
 * @returns {string|symbol} Gibt den Schlüssel zurück.
 */
Funktion toKey(Wert) {
  wenn (Typ des Wertes === 'Zeichenfolge' || istSymbol(Wert)) {
    Rückgabewert
  }
  const Ergebnis = `${Wert}`
  return (Ergebnis == '0' und (1 / Wert) == -UNENDLICH) ? '-0' : Ergebnis
}

Hier werden im Wesentlichen zwei Dinge erledigt.

  • Wenn der Schlüsseltyp String oder Symbol ist, wird er direkt zurückgegeben.
  • Wenn der Schlüssel einen anderen Typ hat, wird er in einen String umgewandelt und zurückgegeben

Die Funktion isSymbol wird hier auch verwendet, um zu bestimmen, ob es sich um einen Symboltyp handelt. Der Code wird hier nicht veröffentlicht. Interessierte Studenten können den Lodash-Quellcode überprüfen.

castPath-Funktion:

importiere isKey aus './isKey.js'
importiere stringToPath aus „./stringToPath.js“
​
/**
 * Wandelt „Wert“ in ein Pfad-Array um, wenn es keins ist.
 *
 * @Privat
 * @param {*} Wert Der zu prüfende Wert.
 * @param {Object} [Objekt] Das Objekt, dessen Schlüssel abgefragt werden sollen.
 * @returns {Array} Gibt das Array mit dem Pfad der gegossenen Eigenschaft zurück.
 */
Funktion castPath(Wert, Objekt) {
  wenn (Array.isArray(Wert)) {
    Rückgabewert
  }
  returniere isKey(Wert, Objekt) ? [Wert] : stringToPath(Wert)
}
​

castPath konvertiert hauptsächlich den Eingabepfad in ein Array, um ihn auf die nachfolgende Durchquerung zum Abrufen tiefer Objekte vorzubereiten.

Hier werden isKey() und stringToPath() verwendet.

isKey ist eine relativ einfache Funktion, um zu bestimmen, ob der aktuelle Wert der Schlüssel eines Objekts ist.

stringToPath behandelt hauptsächlich den Fall, in dem der Eingabepfad eine Zeichenfolge ist, z. B.: 'abc[0].d'

stringToPath-Funktion:

importiere memoizeCapped aus „./memoizeCapped.js“
​
const charCodeOfDot = '.'.charCodeAt(0)
const reEscapeChar = /\(\)?/g
const rePropName = RegExp(
  // Findet eine Übereinstimmung mit allem, was kein Punkt oder keine Klammer ist.
  '[^.[\]]+' + '|' +
  // Oder passen Sie die Eigenschaftsnamen in Klammern an.
  '\[(?:' +
    //Passt auf einen Ausdruck, der kein String ist.
    '([^"'][^[]*)' + '|' +
    // Oder Zeichenfolgen abgleichen (unterstützt das Escapen von Zeichen).
    '(["'])((?:(?!\2)[^\\]|\\.)*?)\2' +
  ')\]'+ '|' +
  // Oder "" als Leerzeichen zwischen aufeinanderfolgenden Punkten oder leeren Klammern abgleichen.
  '(?=(?:\.|\[\])(?:\.|\[\]|$))'
  , 'G')
​
/**
 * Konvertiert „String“ in ein Eigenschaftspfad-Array.
 *
 * @Privat
 * @param {string} string Der zu konvertierende String.
 * @returns {Array} Gibt das Eigenschaftspfad-Array zurück.
 */
const stringToPath = memoizeCapped((string) => {
  const Ergebnis = []
  wenn (string.charCodeAt(0) === charCodeOfDot) {
    Ergebnis.push('')
  }
  string.replace(rePropName, (Übereinstimmung, Ausdruck, Anführungszeichen, Teilzeichenfolge) => {
    let key = match
    wenn (Zitat) {
      Schlüssel = Teilstring.replace(reEscapeChar, '$1')
   }
    sonst wenn (Ausdruck) {
      Schlüssel = Ausdruck.trim()
   }
    Ergebnis.push(Schlüssel)
  })
  Ergebnis zurückgeben
})
​

Hier schließen wir hauptsächlich die . und [] im Pfad aus, analysieren den echten Schlüssel und fügen ihn dem Array hinzu

memoizeCapped-Funktion:

importiere Memoize aus „../memoize.js“
​
/** Wird als maximale Memoize-Cachegröße verwendet. */
const MAX_MEMOIZE_SIZE = 500
​
/**
 * Eine spezielle Version von `memoize`, die die gespeicherten Daten der Funktion löscht.
 * Cache, wenn „MAX_MEMOIZE_SIZE“ überschritten wird.
 *
 * @Privat
 * @param {Function} func Die Funktion, deren Ausgabe gespeichert werden soll.
 * @returns {Function} Gibt die neue gespeicherte Funktion zurück.
 */
Funktion memoizeCapped(Funktion) {
  const Ergebnis = memoize(Funktion, (Schlüssel) => {
    const { cache } = Ergebnis
    wenn (cache.size === MAX_MEMOIZE_SIZE) {
      cache.löschen()
   }
    Eingabetaste
  })
​
  Ergebnis zurückgeben
}
​
Export-Standard-MemoizeCapped
​

Hier ist ein Limit für den zwischengespeicherten Schlüssel, der Cache wird gelöscht, wenn er 500 erreicht

Memoize-Funktion:

Funktion memoize(Funktion, Resolver) {
  wenn (Typ der Funktion !== 'Funktion' || (Resolver != null und Typ des Resolvers !== 'Funktion')) {
    throw new TypeError('Eine Funktion erwartet')
  }
  const memoized = Funktion(...args) {
    const Schlüssel = Resolver? Resolver.apply(diese, Argumente) : Argumente[0]
    const cache = memoized.cache
​
    wenn (cache.hat(Schlüssel)) {
      returniere cache.get(Schlüssel)
   }
    const Ergebnis = func.apply(diese, Argumente)
    memoized.cache = cache.set(Schlüssel, Ergebnis) || Cache
    Ergebnis zurückgeben
  }
  memoized.cache = neu (memoize.Cache || Map)
  Rückkehr auswendig gelernt
}
​
memoize.Cache = Karte

Eigentlich verstehe ich die letzten beiden Funktionen nicht ganz. Wenn der Eingabepfad „abc“ ist, können wir ihn dann nicht einfach in ein Array umwandeln? Warum Closures zum Caching verwenden?

Ich hoffe, dass mir jemand, der sich damit auskennt, eine Antwort geben kann.

Da der Quellcode viele Funktionen verwendet und in verschiedenen Dateien liegt, habe ich diese vereinfacht.

Der vollständige Code lautet wie folgt:

/**
   * Ruft den Wert unter `path` von `object` ab. Wenn der aufgelöste Wert
   * „undefined“, stattdessen wird „defaultValue“ zurückgegeben.
   * @Beispiel
   * const Objekt = { 'a': [{ 'b': { 'c': 3 } }] }
   *
   * bekomme(Objekt, 'a[0].b.c')
   * // => 3
   *
   * bekomme(Objekt, ['a', '0', 'b', 'c'])
   * // => 3
   *
   * bekomme(Objekt, 'abc', 'Standard')
   * // => 'Standard'
   */
  safeGet (Objekt, Pfad, Standardwert) {
    Ergebnis lassen
    wenn (Objekt != null) {
      if (!Array.isArray(Pfad)) {
        const type = Typ des Pfads
        wenn (Typ === 'Zahl' || Typ === 'Boolesch' || Pfad == null ||
        /^\w*$/.test(Pfad) || !(/.|[(?:[^[]]*|(["'])(?:(?!\1)[^\]|\.)*?\1)]/.test(Pfad)) ||
       (Objekt != null && Pfad in Objekt(Objekt))) {
          Pfad = [Pfad]
       } anders {
          const Ergebnis = []
          wenn (Pfad.charCodeAt(0) === '.'.charCodeAt(0)) {
            Ergebnis.push('')
         }
          const rePropName = RegExp(
            // Findet eine Übereinstimmung mit allem, was kein Punkt oder keine Klammer ist.
            '[^.[\]]+|\[(?:([^"'][^[]*)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))'
           , 'G')
          Pfad.ersetzen(rePropName, (Übereinstimmung, Ausdruck, Zitat, Teilzeichenfolge) => {
            let key = match
            wenn (Zitat) {
              Schlüssel = Teilstring.replace(/\(\)?/g, '$1')
           } sonst wenn (Ausdruck) {
              Schlüssel = Ausdruck.trim()
           }
            Ergebnis.push(Schlüssel)
         })
          Pfad = Ergebnis
       }
     }
      lass Index = 0
      Konstante Länge = Pfadlänge
      const toKey = (Wert) => {
        wenn (Typ des Wertes === 'Zeichenfolge') {
          Rückgabewert
       }
        const Ergebnis = `${Wert}`
        return (Ergebnis === '0' && (1 / Wert) === -(1 / 0)) ? '-0' : Ergebnis
     }
      während (Objekt != null und Index < Länge) {
        Objekt = Objekt[toKey(Pfad[Index++])]
     }
      Ergebnis = (Index && Index === Länge)? Objekt: undefiniert
   }
    Rückgabeergebnis === undefiniert? Standardwert: Ergebnis
  }

Der Code ist von lodash übernommen

Quellen:

  • Offizielle Lodash-Dokumentation
  • Github

Zusammenfassen

Dies ist das Ende dieses Artikels zum sicheren Abrufen von Objekten auf tiefer Ebene in Js. Weitere relevante Inhalte zum Abrufen von Objekten auf tiefer Ebene in Js 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!

Das könnte Sie auch interessieren:
  • Konvertierungsmethode für JS-Objekte (Object) und Zeichenfolgen (String)
  • So drucken Sie ein Objekt in js
  • Detaillierte Erklärung von Objekten in Javascript
  • Tiefgreifendes Verständnis des Objektklonens in JavaScript
  • Detaillierte Diskussion des Unterschieds zwischen Arrays und Objekten in js
  • Javascript Objektorientiertes Objekt
  • Einführung in das Erstellen von Objekten mit Object.create() in JavaScript
  • Beispielanalyse für die Zusammenführung von Javascript-Objekten

<<:  MySQL verwendet mysqldump + binlog, um die Prinzipanalyse der gelöschten Datenbank vollständig wiederherzustellen

>>:  So verwenden Sie Nginx zum Erstellen eines statischen Ressourcenservers

Artikel empfehlen

Grundlegendes zur CSS-Eigenschaft „transform-origin“

Vorwort Ich habe vor kurzem eine Feuerwerksanimat...

Importieren von CSS-Dateien unter Verwendung von Beurteilungsbedingungen

Lösung 1: Verwenden Sie bedingten Import im HTML-...

Detaillierte Erklärung des VUE-Reaktionsprinzips

Inhaltsverzeichnis 1. Grundlage des Responsive-Pr...

Beispiel für die Bereitstellung eines Django-Projekts mit Docker

Es ist auch sehr einfach, Django-Projekte mit Doc...

Das Submit-Ereignis des Formulars reagiert nicht

1. Problembeschreibung <br />Wenn JS verwen...

Einige häufige Fehler mit MySQL null

Laut Nullwerten bedeutet der Wert Null in MySQL l...

So ändern Sie das Passwort des Root-Benutzers in MySQL

Methode 1: Verwenden Sie den Befehl SET PASSWORD ...

Tutorial zum Bereitstellen von JDK und Tomcat auf CentOS7 ohne Schnittstelle

1. Installieren Sie xshell6 2. Stellen Sie eine S...

CSS transparenter Rahmen Hintergrund-Clip-Magie

In diesem Artikel wird hauptsächlich die wunderba...