One place for hosting & domains

      Objects

      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/MethodenBeschreibungRückgabe
      set(key, value)Hängt einer Map ein Schlüssel/Wert-Paar anMap-Objekt
      delete(key)Entfernt ein Schlüssel/Wert-Paar von einer Map mithilfe eines SchlüsselsBoolean
      get(key)Gibt einen Wert mithilfe eines Schlüssels zurückWert
      has(key)Überprüft das Vorhandensein eines Elements in einer Map mithilfe eines SchlüsselsBoolean
      clear()Entfernt alle Elemente von einer MapN/A
      keys()Gibt alle Schlüssel in einer Map zurückMapIterator-Objekt
      values()Gibt alle Werte in einer Map zurückMapIterator-Objekt
      entries()Gibt alle Schlüssel und Werte in einer Map als [key, value] zurückMapIterator-Objekt
      forEach()Iteriert über die Map in der Reihenfolge der EinfügungenN/A
      sizeGibt die Anzahl der Elemente in einer Map zurückZahl

      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/MethodenBeschreibungRückgabe
      add(value)Hängt einem Set ein neues Element anSet-Objekt
      delete(value)Entfernt das angegebene Element von einem SetBoolean
      has()Überprüft, ob ein Element in einem Set vorhanden istBoolean
      clear()Entfernt alle Elemente von einem SetN/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ückSetIterator-Objekt
      forEach()Iteriert über das Set in der Reihenfolge der EinfügungenN/A
      sizeGibt die Anzahl der Elemente eines Sets zurückZahl

      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

      Comprendre les objects Map et Set en JavaScript


      L’auteur a choisi le Open Internet/Free Speech Fund comme récipiendaire d’un don dans le cadre du programme Write for Donations.

      En JavaScript, les développeurs passent souvent beaucoup de temps à décider de la structure de données correcte à utiliser. En effet, le choix de la bonne structure de données peut faciliter la manipulation ultérieure de ces données, ce qui permet de gagner du temps et de rendre le code plus facile à comprendre. Les deux structures de données prédominantes pour le stockage des collections de données sont Objets et Tableaux (un type d’objet). Les développeurs utilisent des Objets pour stocker les paires clé/valeur et des Tableaux pour stocker les listes indexées. Toutefois, pour donner plus de flexibilité aux développeurs, la spécification ECMAScript 2015 a introduit deux nouveaux types d’objets itératifs : les objets Map, qui sont des collections ordonnées de paires clé/valeur, et les objets Set, qui sont des collections de valeurs uniques.

      Dans cet article, vous passerez en revue les objets Map et Set, ce qui les rend similaires ou différents des Objets et des Tableaux, les propriétés et méthodes dont ils disposent, et des exemples d’utilisations pratiques.

      Objets Map

      Un objet Map est une collection de paires clé/valeur qui peut utiliser n’importe quel type de données comme clé et peut maintenir l’ordre de ses entrées. Les objets Map comportent des éléments d’Objets (une collection unique de paires clé/valeur) et de Tableaux (une collection ordonnée), mais sont plus proches des Objets sur le plan conceptuel. En effet, bien que la taille et l’ordre des entrées soient préservés comme un Tableau, les entrées elles-mêmes sont des paires clé/valeur comme les Objets.

      Les objets Map peuvent être initialisés avec la nouvelle syntaxe Map() :

      const map = new Map()
      

      Cela nous donne un objet Map vide :

      Output

      Map(0) {}

      Ajout de valeurs à un objet Map

      Vous pouvez ajouter des valeurs à un objet Map avec la méthode set(). Le premier argument sera la clé, et le second la valeur.

      Ce qui suit ajoute trois paires clé/valeur à l’objet Map :

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

      Ici, nous commençons à voir comment les objets Map possèdent à la fois des éléments d’Objets et de Tableaux. Comme dans un Tableau, nous avons une collection indexée à zéro, et nous pouvons également voir combien d’éléments se trouvent par défaut dans l’objet Map. Les objets Map utilisent la syntaxe => pour signifier les paires clé/valeur en tant que key => value :

      Output

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

      Cet exemple ressemble à un objet ordinaire avec des clés en chaîne, mais nous pouvons utiliser n’importe quel type de données comme clé avec des objets Map.

      Outre la définition manuelle de valeurs sur un objet Map, nous pouvons également initialiser un objet Map avec des valeurs existantes. Pour ce faire, nous utilisons un Tableau des Tableaux contenant deux éléments qui représentent chacun une paire clé/valeur ; ce tableau ressemble à ceci :

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

      En utilisant la syntaxe suivante, nous pouvons recréer le même objet Map :

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

      Remarque : cet exemple utilise des virgules de fin de ligne, également appelées “dangling commas”. Il s’agit d’une pratique de formatage JavaScript dans laquelle le dernier élément d’une série lors de la déclaration d’un ensemble de données comporte une virgule finale. Bien que ce choix de formatage puisse être utilisé pour des différences plus nettes et une manipulation plus facile du code, son utilisation ou non est une question de préférence. Pour plus d’informations sur les virgules de fin de ligne, consultez cet article sur les virgules de fin de ligne dans les documents web de MDN.

      Soit dit en passant, cette syntaxe est la même que celle qui résulte de l’appel de Object.entries() sur un Objet. Cela permet de convertir un Objet en un objet Map, comme le montre le bloc de code suivant :

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

      Vous pouvez également transformer un objet Map en un Objet ou un Tableau avec une seule ligne de code.

      Ce qui suit permet de convertir un objet Map en Objet :

      const obj = Object.fromEntries(map)
      

      Il en résultera la valeur suivante de obj :

      Output

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

      Maintenant, convertissons un objet Map en Tableau :

      const arr = Array.from(map)
      

      Il en résultera le tableau suivant pour arr :

      Output

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

      Clés d’objet Map

      Les objets Map acceptent tout type de données comme clé, et n’autorisent pas la duplication des valeurs de la clé. Nous pouvons le démontrer en créant un objet Map et en utilisant des valeurs non linéaires comme clés, ainsi qu’en attribuant deux valeurs à la même clé.

      Tout d’abord, initialisons une carte avec des clés non ordonnées :

      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')
      

      Cet exemple remplacera la première clé de 1 par la suivante, et traitera "1" la chaîne et 1 le chiffre comme des clés uniques :

      Output

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

      Bien qu’il soit communément admis qu’un objet JavaScript ordinaire peut déjà traiter des nombres, des booléens et d’autres types de données primitives comme des clés, ce n’est en fait pas le cas, car les objets changent toutes les clés en chaînes de caractères.

      À titre d’exemple, initialisez un objet avec une clé numérique et comparez la valeur d’une clé numérique 1 et d’une clé "1" en chaîne :

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

      C’est pourquoi si vous essayez d’utiliser un objet comme clé, il imprimera la chaîne de caractères Objet à la place.

      Par exemple, créez un Objet et utilisez-le ensuite comme clé d’un autre Objet :

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

      Il en résultera ce qui suit :

      Output

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

      Ce n’est pas le cas avec un objet Map. Essayez de créer un Objet et de le définir comme la clé d’un objet Map :

      // 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?')
      

      La key de l’élément Map est maintenant l’objet que nous avons créé.

      Output

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

      Il y a une chose importante à noter concernant l’utilisation d’un Objet ou d’un Tableau comme clé : l’objet Map utilise la référence à l’Objet pour comparer l’égalité, et non la valeur littérale de l’Objet. En JavaScript {} === {} renvoie false (faux), car les deux Objets ne sont pas les mêmes deux Objets, bien qu’ayant la même valeur (vide).

      Cela signifie que l’ajout de deux Objets uniques ayant la même valeur créera un objet Map à deux entrées :

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

      Il en résultera ce qui suit :

      Output

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

      Mais en utilisant deux fois la même référence d’Objet, on crée un objet Map avec une seule entrée.

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

      Ce qui donnera le résultat suivant :

      Output

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

      Le second set() met à jour exactement la même clé que le premier, de sorte que nous nous retrouvons avec un objet Map qui n’a qu’une seule valeur.

      Ajout et suppression d’éléments d’un objet Map

      L’un des inconvénients du travail avec les Objets est qu’il peut être difficile de les énumérer, ou de travailler avec toutes les clés ou valeurs. La structure de l’objet Map, en revanche, possède de nombreuses propriétés intégrées qui rendent le travail avec leurs éléments plus direct.

      Nous pouvons initialiser un nouvel objet Map pour démontrer les méthodes et propriétés suivantes : delete(), has(), get(), et size.

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

      Utilisez la méthode has() pour vérifier l’existence d’un élément dans un objet Map. has() renverra un booléen.

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

      Utilisez la méthode get() pour récupérer une valeur par clé.

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

      L’un des avantages particuliers des objets Map par rapport aux Objets est que vous pouvez trouver la taille d’un objet Map à tout moment, comme vous le feriez avec un Tableau. Vous pouvez obtenir le nombre d’articles dans un objet Map avec la propriété size. Cela implique moins d’étapes que la conversion d’un Objet en Tableau pour en déterminer la longueur.

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

      Utilisez la méthode delete() pour supprimer un élément d’un objet Map par clé. La méthode retournera un booléen-true (vrai) si un élément existait et a été supprimé, et false (faux) s’il ne correspondait à aucun élément.

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

      Il en résultera la carte suivante :

      Output

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

      Enfin, un objet Map peut être débarrassé de toutes ses valeurs avec map.clear().

      // Empty a Map
      map.clear()
      

      Il en résultera :

      Output

      Map(0) {}

      Clés, Valeurs et Entrées pour objets Map

      Les objets peuvent récupérer des clés, des valeurs et des entrées en utilisant les propriétés du constructeur d'Objet. Les objets Map, en revanche, disposent de méthodes prototypes qui nous permettent d’obtenir directement les clés, les valeurs et les entrées de l’instance de l’objet Map.

      Les méthodes keys(), values(), et entries() renvoient toutes un MapIterator, qui est similaire à un Tableau en ce sens que vous pouvez utiliser for...of pour boucler les valeurs.

      Voici un autre exemple d’objet Map, que nous pouvons utiliser pour démontrer ces méthodes :

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

      La méthode keys() renvoie les clés :

      map.keys()
      

      Output

      MapIterator {1970, 1980, 1990}

      La méthode values() renvoie les valeurs :

      map.values()
      

      Output

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

      La méthode entries() renvoie un tableau de paires clé/valeur :

      map.entries()
      

      Output

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

      Itération avec objet Map

      Map dispose d’une méthode forEach intégrée, similaire à celle d’un Tableau, pour l’itération intégrée. Cependant, il y a une petite différence dans ce qu’ils répètent. Le rappel du forEach d’un objet Map se fait par la value, la key et l’objet Map lui-même, tandis que la version Tableau se fait par l’élément, l’index et le tableau lui-même.

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

      C’est un grand avantage pour les objets Map par rapport aux Objets, car les Objets doivent être convertis avec keys(), values() ou entries(), et il n’y a pas de moyen simple de récupérer les propriétés d’un Objet sans le convertir.

      Pour le démontrer, parcourons notre objet Map et enregistrons les paires clé/valeur sur la console :

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

      Il en résultera :

      Output

      1970: bell bottoms 1980: leg warmers 1990: flannel

      Comme une boucle for...of se réitère sur des itérables comme objet Map et Tableau, nous pouvons obtenir exactement le même résultat en déstructurant l’ensemble des éléments de l’objet Map :

      // 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}`)
      }
      

      Propriétés et méthodes Map

      Le tableau suivant présente une liste des propriétés et des méthodes Map pour une consultation rapide :

      Propriétés/MéthodesDescriptionRetours
      set(key, value)Ajoute une paire clé/valeur à une carteObjet Map
      delete(key)Supprime une paire clé/valeur d’un objet Map par cléBooléen
      get(key)Retourne une valeur par clévaleur
      has(key)Recherche la présence d’un élément dans un objet Map par cléBooléen
      clear()Supprime tous les éléments d’un objet MapS/O
      keys()Retourne toutes les clés dans un objet MapObjet MapIterator
      values()Retourne toutes les valeurs dans un objet MapObjet MapIterator
      entries()Retourne toutes les clés et valeurs dans un objet Map sous forme de [key, valeur]Objet MapIterator
      forEach()Se réitère dans l’objet Map dans l’ordre d’insertionS/O
      sizeRetourne le nombre d’items dans un objet MapNumber

      Quand utiliser Map

      En résumé, les objets Map sont similaires aux Objets dans la mesure où ils contiennent des paires clé/valeur, mais les objets Map présentent plusieurs avantages par rapport aux Objets :

      • Taille – Les objets Map ont une propriété size, alors que les Objets n’ont pas de moyen intégré pour récupérer leur taille.
      • Itération – Les objets Map sont directement itérables alors que les Objets ne le sont pas.
      • Flexibilité – Les objets Map peuvent avoir n’importe quel type de données (primitives ou Objets) comme clé pour une valeur, alors que les Objets ne peuvent avoir que des chaînes de caractères.
      • Ordonné – Les objets Map conservent leur ordre d’insertion, alors que les Objets n’ont pas d’ordre garanti.

      En raison de ces facteurs, les objets Map constituent une structure de données puissante à prendre en compte. Cependant, les Objets présentent également des avantages importants :

      • JSON – Les Objets fonctionnent parfaitement avec JSON.parse() et JSON.stringify(), deux fonctions essentielles pour travailler avec JSON, un format de données commun que de nombreuses REST API traitent.
      • Travailler avec un seul élément – En travaillant avec une valeur connue dans un Objet, vous pouvez y accéder directement avec la clé sans avoir besoin d’utiliser une méthode, telle que get() d’objet Map.

      Cette liste vous aidera à décider si un objet Map ou un Objet est la bonne structure de données pour votre cas d’utilisation.

      Objet Set

      Un objet Set est une collection de valeurs uniques. Contrairement à un objet Map, un objet Set est conceptuellement plus proche d’un Tableau que d’un Objet, puisqu’il s’agit d’une liste de valeurs et non de paires clé/valeur. Toutefois, l’objet Set ne remplace pas les Tableaux, mais constitue plutôt un complément pour fournir un soutien supplémentaire pour le travail avec des données dupliquées.

      Vous pouvez initialiser les objets Set avec la nouvelle syntaxe Set().

      const set = new Set()
      

      Cela nous donne un objet Set vide :

      Output

      Set(0) {}

      Les éléments peuvent être ajoutés à un objet Set avec la méthode add(). (À ne pas confondre avec la méthode set() disponible pour Map, bien qu’elles soient similaires).

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

      Comme les objets Set ne peuvent contenir que des valeurs uniques, toute tentative d’ajouter une valeur qui existe déjà sera ignorée.

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

      Note : la même comparaison d’égalité qui s’applique aux clés Map s’applique aux items Set. Deux objets qui ont la même valeur mais ne partagent pas la même référence ne seront pas considérés comme égaux.

      Vous pouvez également initialiser les objets Set avec un Tableau de valeurs. S’il y a des valeurs en double dans le tableau, elles seront supprimées de l’objet Set.

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

      Output

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

      Inversement, un objet Set peut être converti en un Tableau avec une ligne de code :

      const arr = [...set]
      

      Output

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

      Set possède un grand nombre de méthodes et de propriétés identiques à celles de Map, notamment delete(), has(), clear() et 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
      

      Notez que Set n’a pas de moyen d’accéder à une valeur par une clé ou un index, comme Map.get(key) ou arr[index].

      Clés, Valeurs et Entrées pour objets Set

      Map et Set ont tous deux des méthodes keys(), values(), et entries() qui renvoient un itérateur. Cependant, si chacune de ces méthodes a un but distinct dans Map, les objets Set n’ont pas de clés, et les clés sont donc un alias pour les valeurs. Cela signifie que keys() et values() renverront toutes deux le même itérateur, et que entries() renverra la valeur deux fois. Il est plus logique de n’utiliser que des values() avec Set, car les deux autres méthodes existent pour la cohérence et la compatibilité croisée avec Map.

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

      Output

      SetIterator {1, 2, 3}

      Itération avec Set

      Comme Map, Set a une méthode intégrée forEach(). Comme les objets Set n’ont pas de clés, le premier et le second paramètre du rappel forEach() renvoient la même valeur, il n’y a donc pas de cas d’utilisation en dehors de la compatibilité avec Map. Les paramètres de forEach() sont (value, key, set).

      forEach() et for...of peuvent tous deux être utilisés sur Set. Tout d’abord, examinons l’itération forEach() :

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

      Ensuite, nous pouvons écrire la version for...of :

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

      Ces deux stratégies donneront les résultats suivants :

      Output

      hi hello good day

      Propriétés et méthodes de Set

      Le tableau suivant présente une liste des propriétés et des méthodes de Set pour une consultation rapide :

      Propriétés/MéthodesDescriptionRetours
      add(value)Ajoute un nouvel élément à un objet SetObjet Set
      delete(value)Supprime l’élément spécifié d’un objet SetBooléen
      has()Recherche la présence d’un item dans un objet SetBooléen
      clear()Supprime tous les éléments d’un objet SetS/O
      keys()Renvoie toutes les valeurs d’un objet Set (identique à values())Objet SetIterator
      values()Renvoie toutes les valeurs d’un objet Set (identique à values()Objet SetIterator
      entries()Retourne toutes les valeurs d’un objet Set comme [value, value]Objet SetIterator
      forEach()Se réitère dans l’objet Set dans l’ordre d’insertionS/O
      sizeRetourne le nombre d’items de l’objet SetNumber

      Quand utiliser Set

      Set est un complément utile à votre boîte à outils JavaScript, en particulier pour travailler avec des valeurs doubles dans les données.

      En une seule ligne, nous pouvons créer un nouveau Tableau sans valeurs doubles à partir d’un Tableau qui a des valeurs doubles.

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

      Il en résultera :

      Output

      (3) [1, 2, 3]

      Set peut être utilisé pour trouver l’union, l’intersection et la différence entre deux ensembles de données. Toutefois, les Tableaux présentent un avantage significatif par rapport aux objets Set pour la manipulation supplémentaire des données en raison des méthodes sort(), map(), filter() et reduce(), ainsi que de la compatibilité directe avec les méthodes JSON.

      Conclusion

      Dans cet article, vous avez appris qu’un objet Map est une collection de paires de clés/valeurs ordonnées, et qu’un objet Set est une collection de valeurs uniques. Ces deux structures de données ajoutent des capacités supplémentaires à JavaScript et simplifient les tâches courantes telles que la recherche de la longueur d’une collection de paires clé/valeur et la suppression des éléments en double d’un ensemble de données, respectivement. D’autre part, les Objets et les Tableaux ont été traditionnellement utilisés pour le stockage et la manipulation de données en JavaScript, et sont directement compatibles avec JSON, ce qui continue à en faire les structures de données les plus essentielles, notamment pour travailler avec les REST API. Les objets Map et Set sont principalement utiles comme structures de données de soutien pour les Objets et les Tableaux.

      Si vous souhaitez en savoir plus sur JavaScript, consultez la page d’accueil de notre série Comment coder en JavaScript, ou parcourez notre série Comment coder en Node.js pour lire des articles sur le développement back-end.



      Source link

      Understanding Map and Set Objects in JavaScript


      The author selected the Open Internet/Free Speech Fund to receive a donation as part of the Write for DOnations program.

      In JavaScript, developers often spend a lot of time deciding the correct data structure to use. This is because choosing the correct data structure can make it easier to manipulate that data later on, saving time and making code easier to comprehend. The two predominant data structures for storing collections of data are Objects and Arrays (a type of object). Developers use Objects to store key/value pairs and Arrays to store indexed lists. However, to give developers more flexibility, the ECMAScript 2015 specification introduced two new types of iterable objects: Maps, which are ordered collections of key/value pairs, and Sets, which are collections of unique values.

      In this article, you will go over the Map and Set objects, what makes them similar or different to Objects and Arrays, the properties and methods available to them, and examples of some practical uses.

      Maps

      A Map is a collection of key/value pairs that can use any data type as a key and can maintain the order of its entries. Maps have elements of both Objects (a unique key/value pair collection) and Arrays (an ordered collection), but are more similar to Objects conceptually. This is because, although the size and order of entries is preserved like an Array, the entries themselves are key/value pairs like Objects.

      Maps can be initialized with the new Map() syntax:

      const map = new Map()
      

      This gives us an empty Map:

      Output

      Map(0) {}

      Adding Values to a Map

      You can add values to a map with the set() method. The first argument will be the key, and the second argument will be the value.

      The following adds three key/value pairs to map:

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

      Here we begin to see how Maps have elements of both Objects and Arrays. Like an Array, we have a zero-indexed collection, and we can also see how many items are in the Map by default. Maps use the => syntax to signify key/value pairs as key => value:

      Output

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

      This example looks similar to a regular object with string-based keys, but we can use any data type as a key with Maps.

      In addition to manually setting values on a Map, we can also initialize a Map with values already. We do this using an Array of Arrays containing two elements that are each key/value pairs, which looks like this:

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

      Using the following syntax, we can recreate the same Map:

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

      Note: This example uses trailing commas, also referred to as dangling commas. This is a JavaScript formatting practice in which the final item in a series when declaring a collection of data has a comma at the end. Though this formatting choice can be used for cleaner diffs and easier code manipulation, whether to use it or not is a matter of preference. For more information on trailing commas, see this Trailing Comma article from the MDN web docs.

      Incidentally, this syntax is the same as the result of calling Object.entries() on an Object. This provides a ready-made way to convert an Object to a Map, as shown in the following code block:

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

      Alternatively, you can turn a Map back into an Object or an Array with a single line of code.

      The following converts a Map to an Object:

      const obj = Object.fromEntries(map)
      

      This will result in the following value of obj:

      Output

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

      Now, let’s convert a Map to an Array:

      const arr = Array.from(map)
      

      This will result in the following Array for arr:

      Output

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

      Map Keys

      Maps accept any data type as a key, and do not allow duplicate key values. We can demonstrate this by creating a map and using non-string values as keys, as well as setting two values to the same key.

      First, let’s initialize a map with non-string keys:

      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')
      

      This example will override the first key of 1 with the subsequent one, and it will treat '1' the string and 1 the number as unique keys:

      Output

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

      Although it is a common belief that a regular JavaScript Object can already handle Numbers, booleans, and other primitive data types as keys, this is actually not the case, because Objects change all keys to strings.

      As an example, initialize an object with a numerical key and compare the value for a numerical 1 key and a stringified "1" key:

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

      This is why if you attempt to use an Object as a key, it will print out the string object Object instead.

      As an example, create an Object and then use it as the key of another Object:

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

      This will yield the following:

      Output

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

      This is not the case with Map. Try creating an Object and setting it as the key of a Map:

      // 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?')
      

      The key of the Map element is now the object we created.

      Output

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

      There is one important thing to note about using an Object or Array as a key: the Map is using the reference to the Object to compare equality, not the literal value of the Object. In JavaScript {} === {} returns false, because the two Objects are not the same two Objects, despite having the same (empty) value.

      That means that adding two unique Objects with the same value will create a Map with two entries:

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

      This will yield the following:

      Output

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

      But using the same Object reference twice will create a Map with one entry.

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

      Which will result in the following:

      Output

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

      The second set() is updating the same exact key as the first, so we end up with a Map that only has one value.

      Getting and Deleting Items from a Map

      One of the disadvantages of working with Objects is that it can be difficult to enumerate them, or work with all the keys or values. The Map structure, by contrast, has a lot of built-in properties that make working with their elements more direct.

      We can initialize a new Map to demonstrate the following methods and properties: delete(), has(), get(), and size.

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

      Use the has() method to check for the existence of an item in a map. has() will return a Boolean.

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

      Use the get() method to retrieve a value by key.

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

      One particular benefit Maps have over Objects is that you can find the size of a Map at any time, like you can with an Array. You can get the count of items in a Map with the size property. This involves fewer steps than converting an Object to an Array to find the length.

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

      Use the delete() method to remove an item from a Map by key. The method will return a Boolean—true if an item existed and was deleted, and false if it did not match any item.

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

      This will result in the following Map:

      Output

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

      Finally, a Map can be cleared of all values with map.clear().

      // Empty a Map
      map.clear()
      

      This will yield:

      Output

      Map(0) {}

      Keys, Values, and Entries for Maps

      Objects can retrieve keys, values, and entries by using the properties of the Object constructor. Maps, on the other hand, have prototype methods that allow us to get the keys, values, and entries of the Map instance directly.

      The keys(), values(), and entries() methods all return a MapIterator, which is similar to an Array in that you can use for...of to loop through the values.

      Here is another example of a Map, which we can use to demonstrate these methods:

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

      The keys() method returns the keys:

      map.keys()
      

      Output

      MapIterator {1970, 1980, 1990}

      The values() method returns the values:

      map.values()
      

      Output

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

      The entries() method returns an array of key/value pairs:

      map.entries()
      

      Output

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

      Iteration with Map

      Map has a built-in forEach method, similar to an Array, for built-in iteration. However, there is a bit of a difference in what they iterate over. The callback of a Map’s forEach iterates through the value, key, and map itself, while the Array version iterates through the item, index, and array itself.

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

      This is a big advantage for Maps over Objects, as Objects need to be converted with keys(), values(), or entries(), and there is not a simple way to retrieve the properties of an Object without converting it.

      To demonstrate this, let’s iterate through our Map and log the key/value pairs to the console:

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

      This will give:

      Output

      1970: bell bottoms 1980: leg warmers 1990: flannel

      Since a for...of loop iterates over iterables like Map and Array, we can get the exact same result by destructuring the array of Map items:

      // 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}`)
      }
      

      Map Properties and Methods

      The following table shows a list of Map properties and methods for quick reference:

      Properties/MethodsDescriptionReturns
      set(key, value)Appends a key/value pair to a MapMap Object
      delete(key)Removes a key/value pair from a Map by keyBoolean
      get(key)Returns a value by keyvalue
      has(key)Checks for the presence of an element in a Map by keyBoolean
      clear()Removes all items from a MapN/A
      keys()Returns all keys in a MapMapIterator object
      values()Returns all values in a MapMapIterator object
      entries()Returns all keys and values in a Map as [key, value]MapIterator object
      forEach()Iterates through the Map in insertion orderN/A
      sizeReturns the number of items in a MapNumber

      When to Use Map

      Summing up, Maps are similar to Objects in that they hold key/value pairs, but Maps have several advantages over objects:

      • Size – Maps have a size property, whereas Objects do not have a built-in way to retrieve their size.
      • Iteration – Maps are directly iterable, whereas Objects are not.
      • Flexibility – Maps can have any data type (primitive or Object) as the key to a value, while Objects can only have strings.
      • Ordered – Maps retain their insertion order, whereas objects do not have a guaranteed order.

      Due to these factors, Maps are a powerful data structure to consider. However, Objects haves some important advantages as well:

      • JSON – Objects work flawlessly with JSON.parse() and JSON.stringify(), two essential functions for working with JSON, a common data format that many REST APIs deal with.
      • Working with a single element – Working with a known value in an Object, you can access it directly with the key without the need to use a method, such as Map’s get().

      This list will help you decide if a Map or Object is the right data structure for your use case.

      Set

      A Set is a collection of unique values. Unlike a Map, a Set is conceptually more similar to an Array than an Object, since it is a list of values and not key/value pairs. However, Set is not a replacement for Arrays, but rather a supplement for providing additional support for working with duplicated data.

      You can initialize Sets with the new Set() syntax.

      const set = new Set()
      

      This gives us an empty Set:

      Output

      Set(0) {}

      Items can be added to a Set with the add() method. (This is not to be confused with the set() method available to Map, although they are similar.)

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

      Since Sets can only contain unique values, any attempt to add a value that already exists will be ignored.

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

      Note: The same equality comparison that applies to Map keys applies to Set items. Two objects that have the same value but do not share the same reference will not be considered equal.

      You can also initialize Sets with an Array of values. If there are duplicate values in the array, they will be removed from the Set.

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

      Output

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

      Conversely, a Set can be converted into an Array with one line of code:

      const arr = [...set]
      

      Output

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

      Set has many of the same methods and properties as Map, including delete(), has(), clear(), and 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
      

      Note that Set does not have a way to access a value by a key or index, like Map.get(key) or arr[index].

      Keys, Values, and Entries for Sets

      Map and Set both have keys(), values(), and entries() methods that return an Iterator. However, while each one of these methods have a distinct purpose in Map, Sets do not have keys, and therefore keys are an alias for values. This means that keys() and values() will both return the same Iterator, and entries() will return the value twice. It makes the most sense to only use values() with Set, as the other two methods exist for consistency and cross-compatibility with Map.

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

      Output

      SetIterator {1, 2, 3}

      Iteration with Set

      Like Map, Set has a built-in forEach() method. Since Sets don’t have keys, the first and second parameter of the forEach() callback return the same value, so there is no use case for it outside of compatibility with Map. The parameters of forEach() are (value, key, set).

      Both forEach() and for...of can be used on Set. First, let’s look at forEach() iteration:

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

      Then we can write the for...of version:

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

      Both of these strategies will yield the following:

      Output

      hi hello good day

      Set Properties and Methods

      The following table shows a list of Set properties and methods for quick reference:

      Properties/MethodsDescriptionReturns
      add(value)Appends a new item to a SetSet Object
      delete(value)Removes the specified item from a SetBoolean
      has()Checks for the presence of an item in a SetBoolean
      clear()Removes all items from a SetN/A
      keys()Returns all values in a Set (same as values())SetIterator object
      values()Returns all values in a Set (same as keys())SetIterator object
      entries()Returns all values in a Set as [value, value]SetIterator object
      forEach()Iterates through the Set in insertion orderN/A
      sizeReturns the number of items in a SetNumber

      When to Use Set

      Set is a useful addition to your JavaScript toolkit, particularly for working with duplicate values in data.

      In a single line, we can create a new Array without duplicate values from an Array that has duplicate values.

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

      This will give:

      Output

      (3) [1, 2, 3]

      Set can be used for finding the union, intersection, and difference between two sets of data. However, Arrays have a significant advantage over Sets for additional manipulation of the data due to the sort(), map(), filter(), and reduce() methods, as well as direct compatibility with JSON methods.

      Conclusion

      In this article, you learned that a Map is a collection of ordered key/value pairs, and that a Set is a collection of unique values. Both of these data structures add additional capabilities to JavaScript and simplify common tasks such as finding the length of a key/value pair collection and removing duplicate items from a data set, respectively. On the other hand, Objects and Arrays have been traditionally used for data storage and manipulation in JavaScript, and have direct compatibility with JSON, which continues to make them the most essential data structures, especially for working with REST APIs. Maps and Sets are primarily useful as supporting data structures for Objects and Arrays.

      If you would like to learn more about JavaScript, check out the homepage for our How To Code in JavaScript series, or browse our How to Code in Node.js series for articles on back-end development.



      Source link