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.
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:
OutputMap(0) {}
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:
OutputMap(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'] ]
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:
Output0: {"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.
Outputkey: {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:
OutputMap(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:
OutputMap(1) {{…} => "Two"}
Das zweite set()
aktualisiert den exakt gleichen Schlüssel wie das erste, sodass wir letztendlich eine Map mit nur einem Wert haben.
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:
OutputMap(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:
OutputMap(0) {}
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()
OutputMapIterator {1970, 1980, 1990}
Die Methode values()
gibt die Werte zurück:
map.values()
OutputMapIterator {"bell bottoms", "leg warmers", "flannel"}
Die Methode entries()
gibt ein Array von Schlüssel/Wert-Paaren zurück:
map.entries()
OutputMapIterator {1970 => "bell bottoms", 1980 => "leg warmers", 1990 => "flannel"}
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:
Output1970: 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}`)
}
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 |
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
, während Objekte keine integrierte Möglichkeit zum Abruf ihrer Größe haben.Aufgrund dieser Faktoren sind Maps eine leistungsstarke Datenstruktur, die in Betracht gezogen werden sollte. Objekte haben jedoch auch einige wichtige Vorteile:
JSON.parse()
und JSON.stringify()
, zwei wesentliche Funktionen zum Arbeiten mit JSON, einem gängigen Datenformat, mit dem viele REST-APIs zu tun haben.get()
verwenden zu müssen.Das hilft Ihnen bei der Entscheidung, ob Map oder Objekt die richtige Datenstruktur für Ihren Anwendungsfall ist.
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:
OutputSet(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'])
OutputSet(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]
.
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()
OutputSetIterator {1, 2, 3}
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:
Outputhi
hello
good day
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 |
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.
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!