JavaScript >> Javascript-Tutorial >  >> Tags >> map

Map und Set in JavaScript verstehen

Dieser Artikel wurde ursprünglich für DigitalOcean geschrieben.

In JavaScript verbringen Entwickler oft viel Zeit mit der Entscheidung über die richtige zu verwendende Datenstruktur. Dies liegt daran, dass die Auswahl der richtigen Datenstruktur die spätere Bearbeitung dieser Daten erleichtern, Zeit sparen und den Code leichter verständlich machen kann. Die beiden vorherrschenden Datenstrukturen zum Speichern von Datensammlungen sind Objekte und Arrays (ein Objekttyp). Entwickler verwenden Objekte zum Speichern von Schlüssel/Wert-Paaren und Arrays zum Speichern von indizierten Listen. Um Entwicklern jedoch mehr Flexibilität zu geben, wurden mit der Spezifikation ECMAScript 2015 zwei neue Typen von iterierbaren Objekten eingeführt:Maps, die geordnete Sammlungen von Schlüssel/Wert-Paaren sind, und Sets, die Sammlungen von eindeutigen Werten sind.

In diesem Artikel werden Sie die Map- und Set-Objekte durchgehen, was sie ähnlich oder anders als Objekte und Arrays macht, die ihnen zur Verfügung stehenden Eigenschaften und Methoden und Beispiele für einige praktische Anwendungen.

Karten

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 enthalten Elemente sowohl von Objekten (einer eindeutigen Sammlung von Schlüssel/Wert-Paaren) als auch von Arrays (einer geordneten Sammlung), sind aber Objekten konzeptionell ähnlicher. Das liegt daran, dass, obwohl die Größe und Reihenfolge der Einträge wie bei einem Array beibehalten wird, die Einträge selbst Schlüssel/Wert-Paare wie Objekte sind.

Karten können mit dem new Map() initialisiert werden Syntax:

const map = new Map()

Dies gibt uns eine leere Map:

Map(0) {}

Hinzufügen von Werten zu einer Karte

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

Im Folgenden werden map drei Schlüssel/Wert-Paare hinzugefügt :

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

Hier beginnen wir zu sehen, wie Maps Elemente sowohl von Objekten als auch von Arrays haben. Wie bei einem Array haben wir eine nullindizierte Sammlung, und wir können auch sehen, wie viele Elemente sich standardmäßig in der Map befinden. Karten verwenden den => Syntax zur Kennzeichnung von Schlüssel/Wert-Paaren als key => value :

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

Dieses Beispiel ähnelt einem normalen Objekt mit zeichenfolgenbasierten Schlüsseln, aber wir können jeden Datentyp als Schlüssel mit Map.

verwenden

Zusätzlich zum manuellen Festlegen von Werten auf einer Map können wir eine Map auch bereits mit Werten initialisieren. Wir tun dies mit einem Array von Arrays, das zwei Elemente enthält, die jeweils Schlüssel/Wert-Paare sind, was so aussieht:

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

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

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

Übrigens ist diese Syntax dieselbe wie das Ergebnis des Aufrufs von Object.entries() auf einem Objekt. Dies bietet eine vorgefertigte Möglichkeit, ein Objekt in eine Karte 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 eine Map mit einer einzigen Codezeile wieder in ein Objekt oder ein Array umwandeln.

Folgendes konvertiert eine Map in ein Objekt:

const obj = Object.fromEntries(map)

Dies ergibt den folgenden Wert von obj :

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

Konvertieren wir nun eine Map in ein Array:

const arr = Array.from(map)

Dies ergibt das folgende Array für arr :

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

Kartenschlüssel

Karten akzeptieren jeden Datentyp als Schlüssel und lassen keine doppelten Schlüsselwerte zu. Wir können dies demonstrieren, indem wir eine Zuordnung erstellen und Nicht-String-Werte als Schlüssel verwenden sowie zwei Werte auf denselben Schlüssel setzen.

Lassen Sie uns zunächst eine Map mit Nicht-String-Schlüsseln initialisieren:

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, und es behandelt '1' die Zeichenfolge und 1 die Nummer als eindeutige Schlüssel:

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

Obwohl allgemein angenommen wird, dass ein normales JavaScript-Objekt bereits Zahlen, boolesche Werte und andere primitive Datentypen als Schlüssel verarbeiten kann, ist dies tatsächlich nicht der Fall, da Objekte alle Schlüssel in Zeichenfolgen umwandeln.

Als Beispiel initialisieren Sie ein Objekt mit einem numerischen Schlüssel und vergleichen den Wert für eine Ziffer 1 key und ein stringifizierter "1" Schlüssel:

// Initialize an object with a numerical key
const obj = { 1: 'One' }

// The key is actually a string
obj[1] === obj['1'] // true

Aus diesem Grund wird beim Versuch, ein Objekt als Schlüssel zu verwenden, die Zeichenfolge object Object ausgegeben stattdessen.

Erstellen Sie beispielsweise 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?',
}

Dies ergibt Folgendes:

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

Bei Map ist das nicht der Fall. Versuchen Sie, ein Objekt zu erstellen und es als Schlüssel einer Karte 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?')

Die key des Map-Elements ist jetzt das Objekt, das wir erstellt haben.

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

Bei der Verwendung eines Objekts oder Arrays als Schlüssel ist eine wichtige Sache zu beachten:Die Map verwendet die Referenz auf das Objekt, um die Gleichheit zu vergleichen, nicht den Literalwert des Objekts. In JavaScript {} === {} gibt false zurück , weil die beiden Objekte nicht dieselben zwei Objekte sind, obwohl sie denselben (leeren) Wert haben.

Das bedeutet, dass das Hinzufügen von zwei eindeutigen Objekten mit demselben 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')

Dies ergibt Folgendes:

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

Die zweimalige Verwendung derselben Objektreferenz erstellt jedoch eine Map mit einem Eintrag.

// Add the same exact object twice as keys to a Map
const obj = {}

map.set(obj, 'One')
map.set(obj, 'Two')

Was zu Folgendem führt:

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

Die zweite set() aktualisiert genau denselben Schlüssel wie der erste, sodass wir am Ende eine Karte haben, die nur einen Wert hat.

Elemente von einer Karte abrufen und löschen

Einer der Nachteile beim Arbeiten mit Objekten ist, dass es schwierig sein kann, sie aufzuzählen oder mit allen Schlüsseln oder Werten zu arbeiten. Im Gegensatz dazu hat die Map-Struktur viele eingebaute Eigenschaften, die das Arbeiten mit ihren Elementen direkter machen.

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 den has() Methode, um zu überprüfen, ob ein Element in einer Karte vorhanden ist. has() gibt einen booleschen Wert zurück.

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

Verwenden Sie den get() Methode, um einen Wert per Schlüssel abzurufen.

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

Ein besonderer Vorteil von Maps gegenüber Objekten ist, dass Sie die Größe der Map jederzeit finden können, wie Sie es bei einem Array können. Mit dem size erhalten Sie die Anzahl der Elemente in einer Karte Eigentum. Dies erfordert weniger Schritte als das Konvertieren eines Objekts in ein Array, um die Länge zu ermitteln.

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

Verwenden Sie den delete() Methode zum Entfernen eines Elements aus einer Karte per Schlüssel. Die Methode gibt einen booleschen Wert zurück – true ob ein Element existierte und gelöscht wurde, und false wenn es mit keinem Artikel übereinstimmte.

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

Dies ergibt die folgende Karte:

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

Schließlich kann eine Map mit map.clear() von allen Werten gelöscht werden .

// Empty a Map
map.clear()

Dies ergibt:

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 von Object verwenden Konstrukteur. Maps hingegen verfügen über Prototypmethoden, die es uns ermöglichen, die Schlüssel, Werte und Einträge der Map-Instanz direkt zu erhalten.

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

Hier ist ein weiteres Beispiel einer Karte, die wir verwenden können, um diese Methoden zu demonstrieren.

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

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

map.keys()
MapIterator {1970, 1980, 1990}

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

map.values()
MapIterator {"bell bottoms", "leg warmers", "flannel"}

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

map.entries()
MapIterator {1970 => "bell bottoms", 1980 => "leg warmers", 1990 => "flannel"}

Iteration mit Map

Map hat einen eingebauten forEach -Methode, ähnlich einem Array, für integrierte Iteration. Es gibt jedoch einen kleinen Unterschied darin, worüber sie iterieren. Der Rückruf des forEach einer Karte durchläuft den value , key , und map selbst, während die Array-Version durch den item iteriert , index und array selbst.

// Map
Map.prototype.forEach((value, key, map) = () => {}

// Array
Array.prototype.forEach((item, index, array) = () => {}

Dies ist ein großer Vorteil für Karten gegenüber Objekten, da Objekte mit keys() konvertiert werden müssen , values() , oder entries() , und es gibt keine einfache Möglichkeit, die Eigenschaften eines Objekts abzurufen, ohne es zu konvertieren.

Um dies zu demonstrieren, lassen Sie uns unsere Map durchlaufen und die Schlüssel/Wert-Paare in der Konsole protokollieren:

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

Dies ergibt:

1970: bell bottoms
1980: leg warmers
1990: flannel

Seit einem for...of Schleife iteriert über Iterables wie Map und Array, wir können genau dasselbe Ergebnis erhalten, indem wir das Array von Map-Elementen destrukturieren:

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

Karteneigenschaften und -methoden

Die folgende Tabelle zeigt eine Liste von Map-Eigenschaften und -Methoden zum schnellen Nachschlagen:

Eigenschaften/Methoden Beschreibung Rückgaben
set(key, value) Hängt ein Schlüssel/Wert-Paar an eine Map an Map Objekt
delete(key) Entfernt ein Schlüssel/Wert-Paar aus einer Zuordnung nach Schlüssel Boolesch
get(key) Gibt einen Wert per Schlüssel zurück Wert
has(key) Überprüft das Vorhandensein eines Elements in einer Map by key Boolesch
clear() Entfernt alle Elemente von einer Karte Nicht zutreffend
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() Durchläuft die Karte in der Reihenfolge der Einfügung Nicht zutreffend
size Gibt die Anzahl der Elemente in einer Karte zurück Nummer

Wann man die Karte verwendet

Zusammenfassend ähneln Karten Objekten darin, dass sie Schlüssel/Wert-Paare enthalten, aber Karten haben mehrere Vorteile gegenüber Objekten:

  • Größe - Karten haben einen size -Eigenschaft, wohingegen Objekte keine eingebaute Möglichkeit haben, ihre Größe abzurufen.
  • Wiederholung - Maps sind direkt iterierbar, Objekte nicht.
  • Flexibilität - Karten können jeden Datentyp (Primitiv oder Objekt) als Schlüssel zu einem Wert haben, während Objekte nur Zeichenketten haben können.
  • Bestellt - Karten behalten ihre Einfügungsreihenfolge bei, während Objekte keine garantierte Reihenfolge haben.

Aufgrund dieser Faktoren sind Karten eine leistungsstarke Datenstruktur, die es zu berücksichtigen gilt. Objects hat jedoch auch einige wichtige Vorteile:

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

Diese Liste hilft Ihnen bei der Entscheidung, ob eine Karte oder ein Objekt die richtige Datenstruktur für Ihren Anwendungsfall ist.

Setzen

Ein Set ist eine Sammlung eindeutiger Werte. Im Gegensatz zu einer Map ähnelt ein Set konzeptionell eher einem Array als einem Objekt, da es sich um eine Liste von Werten und nicht um Schlüssel/Wert-Paare handelt. Set ist jedoch kein Ersatz für Arrays, sondern eher eine Ergänzung zur zusätzlichen Unterstützung beim Arbeiten mit duplizierten Daten.

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

const set = new Set()

Dies gibt uns ein leeres Set:

Set(0) {}

Gegenstände können mit dem add() zu einem Set hinzugefügt werden Methode. (Nicht zu verwechseln mit set() Methode, die Map zur Verfügung steht, obwohl sie ähnlich sind.)

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

Da 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

Sie können Sets auch mit einem Array von Werten initialisieren. Wenn das Array doppelte Werte enthält, werden sie aus dem Set entfernt.

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

Umgekehrt kann ein Set mit einer Codezeile in ein Array umgewandelt werden:

const arr = [...set]
(3) ["Beethoven", "Mozart", "Chopin"]

Set hat viele der gleichen 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 Index zuzugreifen, wie Map.get(key) oder arr[index] .

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

Map und Set haben beide keys() , values() und entries() Methoden, die einen Iterator zurückgeben. Während jedoch jede dieser Methoden in Map einen bestimmten Zweck hat, haben Sets keine Schlüssel, und daher sind Schlüssel ein Alias ​​für Werte. Das bedeutet, dass keys() und values() beide denselben Iterator und entries() zurückgeben gibt den Wert zweimal zurück. Am sinnvollsten ist es, nur values() zu verwenden mit Set, da die beiden anderen Methoden für Konsistenz und Kreuzkompatibilität mit Map existieren.

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

Iteration mit Set

Wie Map hat Set einen eingebauten forEach() Methode. Da Sets keine Schlüssel haben, sind der erste und der zweite Parameter von forEach() Callback gibt den gleichen Wert zurück, daher gibt es dafür keinen Anwendungsfall außerhalb der Kompatibilität mit Map. Die Parameter von forEach() sind (value, key, set) .

Beide forEach() und for...of kann auf Set verwendet werden. Sehen wir uns zunächst forEach() an Iteration:

const set = new Set(['hi', 'hello', 'good day'])

// Iterate a Set with forEach
set.forEach((value) => console.log(value))

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

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

Beide Strategien ergeben Folgendes:

hi
hello
good day

Eigenschaften und Methoden festlegen

Die folgende Tabelle zeigt eine Liste von Set-Eigenschaften und -Methoden zum schnellen Nachschlagen:

Eigenschaften/Methoden Beschreibung Rückgaben
add(value) Hängt ein neues Element an ein Set an Set Objekt
delete(value) Entfernt das angegebene Element aus einem Set Boolean
has() Überprüft das Vorhandensein eines Elements in einem Set Boolesch
clear() Entfernt alle Gegenstände aus einem Set Nicht zutreffend
keys() Gibt alle Werte in einem Set zurück (wie values() ) SetIterator Objekt
values() Gibt alle Werte in einem Set zurück (wie keys() ) SetIterator Objekt
entries() Gibt alle Werte in einem Set als [value, value] zurück SetIterator Objekt
forEach() Durchläuft den Satz in der Reihenfolge der Einfügung Nicht zutreffend
size Gibt die Anzahl der Elemente in einem Set zurück Nummer

Wann Set verwendet werden sollte

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

In einer einzigen Zeile können wir aus einem Array mit doppelten Werten ein neues Array ohne doppelte Werte erstellen.

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

Dies ergibt:

(3) [1, 2, 3]

Set kann verwendet werden, um die Vereinigung, Schnittmenge und Differenz zwischen zwei Datensätzen zu finden. Arrays haben jedoch einen erheblichen Vorteil gegenüber Sets für die zusätzliche Manipulation der Daten aufgrund des sort() , map() , filter() , und reduce() Methoden sowie direkte Kompatibilität mit JSON Methoden.

Fazit

In diesem Artikel haben Sie gelernt, dass eine Map eine Sammlung geordneter Schlüssel/Wert-Paare ist und dass ein Set eine Sammlung eindeutiger Werte ist. Diese beiden Datenstrukturen fügen zusätzliche Funktionen zu JavaScript hinzu und vereinfachen allgemeine Aufgaben wie das Ermitteln der Länge einer Sammlung von Schlüssel/Wert-Paaren bzw. das Entfernen doppelter Elemente aus einem Datensatz. Andererseits wurden Objekte und Arrays traditionell für die Datenspeicherung und -bearbeitung in JavaScript verwendet und sind direkt mit JSON kompatibel, was sie weiterhin zu den wichtigsten Datenstrukturen macht, insbesondere für die Arbeit mit REST-APIs. Maps und Sets sind hauptsächlich als unterstützende Datenstrukturen für Objekte und Arrays nützlich.

Wenn Sie mehr über JavaScript erfahren möchten, sehen Sie sich auf der Homepage unsere Reihe How To Code in JavaScript an oder durchsuchen Sie unsere Reihe How to Code in Node.js nach Artikeln zur Back-End-Entwicklung.