One place for hosting & domains

      Grundlagen

      Grundlagen von Map und Set Objects in JavaScript


      Der Autor hat den Open Internet/Free Speech Fund dazu ausgewählt, eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

      In JavaScript verbringen Entwickler oft viel Zeit bei der Entscheidung, welche Datenstruktur sie verwenden sollen. Dies liegt daran, dass die Auswahl der richtigen Datenstruktur die spätere Datenbearbeitung erleichtert, Zeit spart und Code leichter verständlich macht. Die beiden vorherrschenden Datenstrukturen zur Speicherung von Datensammlungen sind Objekte und Arrays (ein Objekttyp). Entwickler verwenden Objekte zum Speichern von Schlüssel/Wert-Paaren und Arrays zum Speichern indizierter Listen. Um Entwicklern jedoch mehr Flexibilität zu geben, hat die Spezifikation ECMAScript 2015 zwei neue Arten von iterierbaren Objekten eingeführt: Maps, d. h. geordnete Sammlungen von Schlüssel/Wert-Paaren, und Sets, d. h. Sammlungen von eindeutigen Werten.

      In diesem Artikel lernen Sie die Objekte Map und Set kennen sowie ihre Ähnlichkeiten oder Unterschiede zu Objekten und Arrays, ihre verfügbaren Eigenschaften und Methoden und Beispiele praktischer Anwendungen.

      Maps

      Eine Map ist eine Sammlung von Schlüssel/Wert-Paaren, die jeden Datentyp als Schlüssel verwenden und die Reihenfolge ihrer Einträge beibehalten kann. Maps haben Elemente von Objekten (ein eindeutiges Schlüssel/Wert-Paar) und Arrays (eine geordnete Sammlung), sie sind jedoch konzeptionell den Objekten ähnlicher. Das liegt daran, dass die Einträge selbst Schlüssel/Wert-Paare wie Objekte sind, obwohl die Größe und Reihenfolge der Einträge wie bei einem Array beibehalten werden.

      Maps können mit der Syntax new Map() initialisiert werden:

      const map = new Map()
      

      Dadurch erhalten Sie eine leere Map:

      Output

      Map(0) {}

      Einer Map Werte hinzufügen

      Mit der Methode set() können Sie einer Map Werte hinzufügen. Das erste Argument ist der Schlüssel und das zweite Argument ist der Wert.

      Das Folgende fügt der map drei Schlüssel/Wert-Paare hinzu:

      map.set('firstName', 'Luke')
      map.set('lastName', 'Skywalker')
      map.set('occupation', 'Jedi Knight')
      

      Hier sehen wir, dass Maps Elemente von Objekten und Arrays haben. Wie bei einem Array haben wir eine nullindizierte Sammlung und wir können auch sehen, wie viele Elemente standardmäßig in der Map sind. Maps verwenden die Syntax => um Schlüssel/Wert-Paare als key => value zu kennzeichnen:

      Output

      Map(3) 0: {"firstName" => "Luke"} 1: {"lastName" => "Skywalker"} 2: {"occupation" => "Jedi Knight"}

      Dieses Beispiel sieht ähnlich wie ein reguläres Object mit Schlüsseln basierend auf Zeichenfolgen aus, aber mit Maps können wir jeden Datentyp als Schlüssel verwenden.

      Zusätzlich zur manuellen Einstellung von Werten auf einer Map können wir eine Map auch bereits mit Werten initialisieren. Das tun wir mit einem Array von Arrays, das zwei Elemente enthält, die jeweils Schlüssel/Wert-Paare sind. Das sieht folgendermaßen aus:

      [ [ 'key1', 'value1'], ['key2', 'value2'] ]
      

      Mit der folgenden Syntax können wir die gleiche Map neu erstellen:

      const map = new Map([
        ['firstName', 'Luke'],
        ['lastName', 'Skywalker'],
        ['occupation', 'Jedi Knight'],
      ])
      

      Anmerkung: In diesem Beispiel werden nachgestellte Kommas – auch nachstehende Kommas genannt – verwendet. Dies ist eine übliche Formatierung bei JavaScript, bei der das letzte Element in einer Reihe ein Komma am Ende hat, wenn eine Sammlung von Daten deklariert wird. Diese Formatierung kann für sauberere diffs und leichtere Code-Bearbeitung gewählt werden, ihre Anwendung ist jedoch optional. Weitere Informationen zu nachgestellten Kommas finden Sie im Artikel Nachgestelltes Komma in den MDN Web-Dokumenten.

      Zufälligerweise ist diese Syntax die gleiche wie das Ergebnis des Aufrufs Object.entries() auf einem Objekt. Das ist eine gebrauchsfertige Möglichkeit, ein Objekt in eine Map umzuwandeln, wie im folgenden Codeblock gezeigt:

      const luke = {
        firstName: 'Luke',
        lastName: 'Skywalker',
        occupation: 'Jedi Knight',
      }
      
      const map = new Map(Object.entries(luke))
      

      Alternativ können Sie mit einer einzelnen Codezeile eine Map wieder in ein Objekt oder ein Array umwandeln.

      Folgendes wandelt eine Map in ein Objekt um:

      const obj = Object.fromEntries(map)
      

      Dadurch ergibt sich der folgende Werte von obj:

      Output

      {firstName: "Luke", lastName: "Skywalker", occupation: "Jedi Knight"}

      Jetzt wandeln wir eine Map in ein Array um:

      const arr = Array.from(map)
      

      Dadurch ergibt sich das folgende Array für arr:

      Output

      [ ['firstName', 'Luke'], ['lastName', 'Skywalker'], ['occupation', 'Jedi Knight'] ]

      Map-Schlüssel

      Maps akzeptieren jeden Datentyp als Schlüssel und lassen das Duplizieren von Schlüsselwerten nicht zu. Zur Veranschaulichung können wir eine Map erstellen und Werte ohne Zeichenfolgen als Schlüssel verwenden sowie zwei Werte dem gleichen Schlüssel zuweisen.

      Zuerst initialisieren wir eine Map mit Schlüsseln ohne Zeichenfolgen:

      const map = new Map()
      
      map.set('1', 'String one')
      map.set(1, 'This will be overwritten')
      map.set(1, 'Number one')
      map.set(true, 'A Boolean')
      

      Dieses Beispiel überschreibt den ersten Schlüssel von 1 mit dem nachfolgenden Schlüssel und behandelt die Zeichenfolge '1' und die Zahl 1 als eindeutige Schlüssel:

      Output

      0: {"1" => "String one"} 1: {1 => "Number one"} 2: {true => "A Boolean"}

      Obwohl viele glauben, dass ein reguläres JavaScript-Objekt bereits mit Zahlen, Booleans und anderen primitiven Datentypen wie Schlüssel umgehen kann, ist das nicht der Fall, da Objekte alle Schlüssel in Zeichenfolgen umändern.

      Initialisieren Sie zum Beispiel ein Objekt mit einem numerischen Schlüssel und vergleichen Sie den Wert mit einem numerischen Schlüssel 1 und einem Zeichenfolgen-Schlüssel "1":

      // Initialize an object with a numerical key
      const obj = { 1: 'One' }
      
      // The key is actually a string
      obj[1] === obj['1']  // true
      

      Das ist der Grund, weshalb stattdessen die Zeichenfolge object Object gedruckt wird, wenn Sie versuchen, ein Objekt als Schlüssel zu verwenden.

      Erstellen Sie zum Beispiel ein Objekt und verwenden Sie es dann als Schlüssel eines anderen Objekts:

      // Create an object
      const objAsKey = { foo: 'bar' }
      
      // Use this object as the key of another object
      const obj = {
        [objAsKey]: 'What will happen?'
      }
      

      Dadurch erhalten Sie Folgendes:

      Output

      {[object Object]: "What will happen?"}

      Dies ist nicht der Fall mit Map. Versuchen Sie, ein Objekt zu erstellen und es als Schlüssel einer Map festzulegen:

      // Create an object
      const objAsKey = { foo: 'bar' }
      
      const map = new Map()
      
      // Set this object as the key of a Map
      map.set(objAsKey, 'What will happen?')
      

      Der key des Map-Elements ist nun das Objekt, das wir erstellt haben.

      Output

      key: {foo: "bar"} value: "What will happen?"

      Folgendes ist bei der Verwendung von Objekt oder Array als Schlüssel wichtig zu beachten: Die Map verwendet zum Vergleich der Gleichheit die Referenz zum Objekt, nicht den Literalwert des Objekts. In JavaScript gibt {} === {} false zurück, da die beiden Objekte nicht die gleichen zwei Objekte sind, obwohl sie den gleichen (leeren) Wert haben.

      Das bedeutet, dass das Hinzufügen von zwei eindeutigen Objekten mit dem gleichen Wert eine Map mit zwei Einträgen erstellt:

      // Add two unique but similar objects as keys to a Map
      map.set({}, 'One')
      map.set({}, 'Two')
      

      Dadurch erhalten Sie Folgendes:

      Output

      Map(2) {{…} => "One", {…} => "Two"}

      Wenn Sie dieselbe Objekt-Referenz zweimal verwenden, wird jedoch eine Map mit einem Eintrag erstellt.

      // Add the same exact object twice as keys to a Map
      const obj = {}
      
      map.set(obj, 'One')
      map.set(obj, 'Two')
      

      Das führt zu Folgendem:

      Output

      Map(1) {{…} => "Two"}

      Das zweite set() aktualisiert den exakt gleichen Schlüssel wie das erste, sodass wir letztendlich eine Map mit nur einem Wert haben.

      Elemente von einer Map abrufen und löschen

      Einer der Nachteile von Objekten ist, dass es schwierig sein kann, diese aufzuzählen oder mit allen Schlüsseln oder Werten zu arbeiten. Die Map-Struktur hat dagegen eine Menge von integrierten Eigenschaften, wodurch man direkter mit ihren Elementen arbeitet kann.

      Wir können eine neue Map initialisieren, um die folgenden Methoden und Eigenschaften zu demonstrieren: delete(), has(), get() und size.

      // Initialize a new Map
      const map = new Map([
        ['animal', 'otter'],
        ['shape', 'triangle'],
        ['city', 'New York'],
        ['country', 'Bulgaria'],
      ])
      

      Verwenden Sie die Methode has(), um das Vorhandensein eines Elements in einer Map zu überprüfen. has() gibt ein Boolean zurück.

      // Check if a key exists in a Map
      map.has('shark') // false
      map.has('country') // true
      

      Verwenden Sie die Methode get(), um mit einem Schlüssel einen Wert abzurufen.

      // Get an item from a Map
      map.get('animal') // "otter"
      

      Ein besonderer Vorteil von Maps gegenüber Objekten ist, dass Sie jederzeit die Größe einer Map finden können, so wie es bei einem Array möglich ist. Die Anzahl der Elemente in einer Map können Sie mit der Eigenschaft size abrufen. Dies beinhaltet weniger Schritte als die Umwandlung eines Objekts in ein Array, um die length zu finden.

      // Get the count of items in a Map
      map.size // 4
      

      Verwenden Sie die Methode delete(), um ein Element mithilfe eines Schlüssels von einer Map zu entfernen. Die Methode gibt ein Boolean true zurück, wenn ein Element vorhanden war und gelöscht wurde, und false, wenn es mit keinem Element übereinstimmt.

      // Delete an item from a Map by key
      map.delete('city') // true
      

      Dadurch ergibt sich folgende Map:

      Output

      Map(3) {"animal" => "otter", "shape" => "triangle", "country" => "Bulgaria"}

      Zu guter Letzt können alle Werte in einer Map mit map.clear() gelöscht werden.

      // Empty a Map
      map.clear()
      

      Dadurch erhalten Sie Folgendes:

      Output

      Map(0) {}

      Schlüssel, Werte und Einträge für Maps

      Objekte können Schlüssel, Werte und Einträge abrufen, indem sie die Eigenschaften des Objekt-Konstruktors verwenden. Maps hingegen haben Prototyp-Methoden, die es uns ermöglichen, die Schlüssel, Werte und Einträge der Map-Instanz direkt abzurufen.

      Die Methoden keys()​​​, values() und entries() geben alle einen MapIterator zurück, der insofern einem Array ähnlich ist, als Sie for...of verwenden können, um die Werte zu durchlaufen.

      Hier ist ein weiteres Beispiel einer Map, die wir zur Demonstration dieser Methoden verwenden können:

      const map = new Map([
        [1970, 'bell bottoms'],
        [1980, 'leg warmers'],
        [1990, 'flannel'],
      ])
      

      Die Methode keys() gibt die Schlüssel zurück:

      map.keys()
      

      Output

      MapIterator {1970, 1980, 1990}

      Die Methode values() gibt die Werte zurück:

      map.values()
      

      Output

      MapIterator {"bell bottoms", "leg warmers", "flannel"}

      Die Methode entries() gibt ein Array von Schlüssel/Wert-Paaren zurück:

      map.entries()
      

      Output

      MapIterator {1970 => "bell bottoms", 1980 => "leg warmers", 1990 => "flannel"}

      Iteration mit Map

      Map verfügt – ähnlich wie bei einem Array – über eine integrierte forEach-Methode für die integrierte Iteration. Worüber sie iterieren, unterscheidet sich jedoch ein wenig. Das Callback von forEach einer Map iteriert über value, key und die map selbst, während die Array-Version über item, index und das array selbst iteriert.

      // Map
      Map.prototype.forEach((value, key, map) = () => {})
      
      // Array
      Array.prototype.forEach((item, index, array) = () => {})
      

      Das ist ein großer Vorteil für Maps gegenüber Objekten, da Objekte mit keys(), values() oder entries() umgewandelt werden müssen und es keinen einfachen Weg gibt, die Eigenschaften eines Objekts ohne Umwandlung abzurufen.

      Um dies zu demonstrieren, iterieren wir über unsere Map und protokollieren die Schlüssel/Wert-Paare in der Konsole:

      // Log the keys and values of the Map with forEach
      map.forEach((value, key) => {
        console.log(`${key}: ${value}`)
      })
      

      Dies ergibt:

      Output

      1970: bell bottoms 1980: leg warmers 1990: flannel

      Da eine for...of-Schleife über Iterablen wie Map und Array iteriert, können wir durch Destrukturierung des Arrays der Map-Elemente genau das gleiche Ergebnis erhalten.

      // Destructure the key and value out of the Map item
      for (const [key, value] of map) {
        // Log the keys and values of the Map with for...of
        console.log(`${key}: ${value}`)
      }
      

      Eigenschaften und Methoden von Map

      Die folgende Tabelle zeigt eine Liste der Eigenschaften und Methoden von Map für einen schnellen Überblick:

      Eigenschaften/Methoden Beschreibung Rückgabe
      set(key, value) Hängt einer Map ein Schlüssel/Wert-Paar an Map-Objekt
      delete(key) Entfernt ein Schlüssel/Wert-Paar von einer Map mithilfe eines Schlüssels Boolean
      get(key) Gibt einen Wert mithilfe eines Schlüssels zurück Wert
      has(key) Überprüft das Vorhandensein eines Elements in einer Map mithilfe eines Schlüssels Boolean
      clear() Entfernt alle Elemente von einer Map N/A
      keys() Gibt alle Schlüssel in einer Map zurück MapIterator-Objekt
      values() Gibt alle Werte in einer Map zurück MapIterator-Objekt
      entries() Gibt alle Schlüssel und Werte in einer Map als [key, value] zurück MapIterator-Objekt
      forEach() Iteriert über die Map in der Reihenfolge der Einfügungen N/A
      size Gibt die Anzahl der Elemente in einer Map zurück Zahl

      Wann man Map verwendet

      Zusammengefasst kann man sagen: Maps sind insofern Objekten ähnlich, als sie Schlüssel/Wert-Paare enthalten, aber Maps haben mehrere Vorteile gegenüber Objekten:

      • Size – Maps haben die Eigenschaft size, während Objekte keine integrierte Möglichkeit zum Abruf ihrer Größe haben.
      • Iteration – Maps sind direkt iterierbar, Objekte nicht.
      • Flexibilität – Maps können einen beliebigen Datentyp (primitiv oder Objekt) als Schlüssel für einen Wert haben, während Objekte nur Zeichenfolgen haben können.
      • Geordnet – Maps behalten die Reihenfolge ihrer Einfügungen bei, während Objekte keine garantierte Reihenfolge haben.

      Aufgrund dieser Faktoren sind Maps eine leistungsstarke Datenstruktur, die in Betracht gezogen werden sollte. Objekte haben jedoch auch einige wichtige Vorteile:

      • JSON – Objekte funktionieren einwandfrei mit JSON.parse() und JSON.stringify(), zwei wesentliche Funktionen zum Arbeiten mit JSON, einem gängigen Datenformat, mit dem viele REST-APIs zu tun haben.
      • Mit einem einzelnen Element arbeiten – Wenn Sie mit einem bekannten Wert in einem Objekt arbeiten, können Sie direkt mit dem Schlüssel darauf zugreifen, ohne eine Methode wie Maps get() verwenden zu müssen.

      Das hilft Ihnen bei der Entscheidung, ob Map oder Objekt die richtige Datenstruktur für Ihren Anwendungsfall ist.

      Set

      Ein Set ist eine Sammlung von eindeutigen Werten. Im Gegensatz zu einer Map ist ein Set einem Array konzeptionell ähnlicher als einem Objekt, da es eine Liste von Werten und nicht Schlüssel/Wert-Paaren ist. Set ist jedoch kein Ersatz für Arrays, sondern eine Ergänzung für die zusätzliche Unterstützung der Arbeit mit duplizierten Daten.

      Sie können Sets mit der Syntax new Set() initialisieren.

      const set = new Set()
      

      Dadurch erhalten Sie ein leeres Set:

      Output

      Set(0) {}

      Elemente können einem Set mit der Methode add() hinzugefügt werden. (Das darf nicht mit der Methode set() für Map verwechselt werden, obwohl sie ähnlich ist.)

      // Add items to a Set
      set.add('Beethoven')
      set.add('Mozart')
      set.add('Chopin')
      

      Nachdem Sets nur eindeutige Werte enthalten können, wird jeder Versuch, einen bereits vorhandenen Wert hinzuzufügen, ignoriert.

      set.add('Chopin') // Set will still contain 3 unique values
      

      Anmerkung: Derselbe Gleichheits-Vergleich, der für Map-Schlüssel gilt, gilt auch für Set-Elemente. Zwei Objekte, die den gleichen Wert haben, aber nicht die gleiche Referenz teilen, werden nicht als gleich angesehen.

      Sie können Sets auch mit einem Array von Werten initialisieren. Wenn im Array doppelte Werte vorhanden sind, werden sie vom Set entfernt.

      // Initialize a Set from an Array
      const set = new Set(['Beethoven', 'Mozart', 'Chopin', 'Chopin'])
      

      Output

      Set(3) {"Beethoven", "Mozart", "Chopin"}

      Umgekehrt kann ein Set mit einer Code-Zeile in ein Array umgewandelt werden:

      const arr = [...set]
      

      Output

      (3) ["Beethoven", "Mozart", "Chopin"]

      Set hat viele gleiche Methoden und Eigenschaften wie Map, einschließlich delete(),​has(), clear() und size.

      // Delete an item
      set.delete('Beethoven') // true
      
      // Check for the existence of an item
      set.has('Beethoven') // false
      
      // Clear a Set
      set.clear()
      
      // Check the size of a Set
      set.size // 0
      

      Beachten Sie, dass Set keine Möglichkeit hat, auf einen Wert über einen Schlüssel oder einen Index zuzugreifen, wie Map.get(key) oder arr[index].

      Schlüssel, Werte und Einträge für Sets

      Map und Set haben beide die Methoden keys(), values() und entries(), die einen Iterator zurückgeben. Bei Map hat jede dieser Methoden ihren eigenen Zweck. Sets haben jedoch keine Schlüssel und daher sind Schlüssel ein Alias für Werte. Das bedeutet, dass keys() und values() beide den gleichen Iterator zurückgeben und entries() den Wert zweimal zurückgeben. Es ist am sinnvollsten, nur values() mit Set zu verwenden, da die beiden anderen Methoden der Einheitlichkeit und übergreifenden Kompatibilität mit Map dienen.

      const set = new Set([1, 2, 3])
      // Get the values of a set
      set.values()
      

      Output

      SetIterator {1, 2, 3}

      Iteration mit Set

      Wie Map hat auch Set eine integrierte forEach()-Methode. Da Sets keine Schlüssel haben, geben der erste und der zweite Parameter des forEach()-Callbacks den gleichen Wert zurück, sodass es dafür keinen Anwendungsfall außerhalb der Kompatibilität mit Map gibt. Die Parameter von forEach() sind (value, key, set).

      Sowohl forEach() als auch for...of können für Set verwendet werden. Sehen wir uns zuerst die Iteration forEach() an:

      const set = new Set(['hi', 'hello', 'good day'])
      
      // Iterate a Set with forEach
      set.forEach((value) => console.log(value))
      

      Dann können wir die Version for...of schreiben:

      // Iterate a Set with for...of
      for (const value of set) {  
          console.log(value);
      }
      

      Beide Strategien ergeben Folgendes:

      Output

      hi hello good day

      Eigenschaften und Methoden von Set

      Die folgende Tabelle zeigt eine Liste der Eigenschaften und Methoden von Set für einen schnellen Überblick:

      Eigenschaften/Methoden Beschreibung Rückgabe
      add(value) Hängt einem Set ein neues Element an Set-Objekt
      delete(value) Entfernt das angegebene Element von einem Set Boolean
      has() Überprüft, ob ein Element in einem Set vorhanden ist Boolean
      clear() Entfernt alle Elemente von einem Set N/A
      keys() Gibt alle Werte eines Sets zurück (genau wie values()) SetIterator-Objekt
      values() Gibt alle Werte eines Sets zurück (genau wie keys()) SetIterator-Objekt
      entries() Gibt alle Werte eines Sets als [value, value] zurück SetIterator-Objekt
      forEach() Iteriert über das Set in der Reihenfolge der Einfügungen N/A
      size Gibt die Anzahl der Elemente eines Sets zurück Zahl

      Wann man Set verwendet

      Set ist eine nützliche Ergänzung zu Ihrem JavaScript-Toolkit, insbesondere für die Arbeit mit doppelten Werten in Daten.

      In einer einzelnen Zeile können wir ein neues Array ohne doppelte Werte eines Arrays, das doppelte Werte hat, erstellen.

      const uniqueArray = [ ...new Set([1, 1, 2, 2, 2, 3])] // (3) [1, 2, 3]
      

      Dies ergibt:

      Output

      (3) [1, 2, 3]

      Set kann verwendet werden, um nach Union, Intersection und Difference zwischen zwei Datensätzen zu suchen. Arrays haben Sets gegenüber jedoch den erheblichen Vorteil der zusätzlichen Datenmanipulation aufgrund der Methoden sort(), map(), filter() und reduce() sowie der direkten Kompatibilität mit JSON-Methoden.

      Zusammenfassung

      In diesem Artikel haben Sie gelernt, dass eine Map eine Sammlung von geordneten Schlüssel/Wert-Paaren und ein Set eine Sammlung von eindeutigen Werten ist. Beide Datenstrukturen fügen JavaScript zusätzliche Fähigkeiten hinzu und vereinfachen jeweils gängige Aufgaben wie das Auffinden der Länge eines Schlüssel/Wertpaares und das Entfernen doppelter Elemente aus einem Datensatz. Andererseits werden Objekte und Arrays traditionell für die Datenspeicherung und -Bearbeitung in JavaScript verwendet und haben direkte Kompatibilität mit JSON, wodurch sie weiterhin die wichtigsten Datenstrukturen bleiben, insbesondere für die Arbeit mit REST-APIs. Maps und Sets sind in erster Linie nützlich als unterstützende Datenstrukturen für Objekte und Arrays.

      Wenn Sie mehr über JavaScript erfahren möchten, besuchen Sie unsere Homepage für unsere Reihe So codieren Sie in JavaScript oder durchsuchen Sie unsere Reihe So codieren Sie in Node.js für Artikel über Back-End-Entwicklung.



      Source link