Menu

JavaScript Map und Set: Wann lohnt sich der Wechsel?

Wie Map und Set in JavaScript funktionieren, worin sie sich von Objekten und Arrays unterscheiden – und wann sich der Griff dazu wirklich auszahlt.

Zwei Collections jenseits von Object und Array

Für die meisten JavaScript-Programme reichen einfache Objekte und Arrays völlig aus – aber sie wurden eben nicht für jeden Anwendungsfall entworfen. Genau hier kommen Map und Set ins Spiel: zwei eingebaute Collections, die zwei konkrete Lücken schließen – Lookups mit Schlüsseln, die keine Strings sind, und die schnelle Prüfung auf Zugehörigkeit ohne Duplikate.

Beide sind seit ES2015 Teil der Sprache. Sie sind iterierbar, haben eine .size-Eigenschaft und lassen sich problemlos mit dem Spread-Operator kombinieren. Das mentale Modell ist angenehm einfach:

  • Map – wie ein Objekt, aber die Schlüssel dürfen beliebig sein und die Reihenfolge bleibt erhalten.
  • Set – wie ein Array, aber jeder Wert kommt nur einmal vor und das Nachschlagen ist schnell.

Eine Map erstellen und verwenden

Eine Map speichert Schlüssel-Wert-Paare. Du erzeugst sie mit new Map() und arbeitest dann mit .set(), .get(), .has() und .delete():

index.js
Output
Click Run to see the output here.

Du kannst dem Konstruktor auch direkt ein Array aus [key, value]-Paaren übergeben, um die Map vorzubefüllen:

index.js
Output
Click Run to see the output here.

Diese Struktur aus Zwei-Element-Arrays begegnet dir bei Maps ständig – genau so werden Einträge beim Iterieren dargestellt.

Map vs. Object: Wozu der Aufwand?

Auf den ersten Blick machen normale Objekte dasselbe. In den meisten Fällen stimmt das auch. Aber Map räumt ein paar konkrete Stolperfallen aus dem Weg:

index.js
Output
Click Run to see the output here.

Objekte erben von Object.prototype. Dadurch existieren Keys wie toString, constructor oder hasOwnProperty von Haus aus auf jedem Objekt. Eine Map bringt diesen Ballast nicht mit – drin sind nur die Keys, die du selbst gesetzt hast.

Die weiteren Unterschiede, die du kennen solltest:

  • Beliebige Key-Typen. Eine Map akzeptiert Objekte, Funktionen, Zahlen und Booleans als Keys. Objekte wandeln Nicht-String-Keys dagegen klammheimlich in Strings um: obj[1] und obj["1"] zeigen auf denselben Slot.
  • Garantierte Einfügereihenfolge. Beim Iterieren kommen die Einträge einer Map in genau der Reihenfolge heraus, in der du sie hinzugefügt hast. Objekte verhalten sich meistens ähnlich, aber numerisch aussehende String-Keys werden nach vorn sortiert – eine fiese Stolperfalle.
  • Eingebaute Größe. map.size ist O(1). Bei einem Objekt müsstest du Object.keys(obj).length schreiben, was jedes Mal ein neues Array aufbaut.
  • Optimiert für viele Änderungen. JavaScript-Engines sind bei Maps auf häufiges Hinzufügen und Entfernen getrimmt. Objekte sind dagegen auf eine stabile Form ausgelegt.

Nimm ein Objekt, wenn du einen Datensatz mit festen String-Keys modellierst ({ name, email, age }). Greif zu einer Map, sobald die Keys dynamisch sind, keine Strings sein sollen oder du ständig Einträge hinzufügst und wieder entfernst.

Map iterieren in JavaScript

Maps sind iterierbar. Das heißt: for...of funktioniert direkt, und jeden Eintrag per Destructuring zu zerlegen fühlt sich völlig natürlich an:

index.js
Output
Click Run to see the output here.

Wenn du nur die Keys oder nur die Values brauchst, greifst du zu .keys() bzw. .values(). Und falls du lieber damit arbeitest: .forEach() gibt's natürlich auch:

index.js
Output
Click Run to see the output here.

Um eine Map wieder in ein Objekt oder ein Array umzuwandeln, nutzt du den Spread-Operator:

index.js
Output
Click Run to see the output here.

Set erstellen und verwenden

Ein Set speichert nur eindeutige Werte. Wenn du einen Wert hinzufügst, der bereits enthalten ist, passiert schlicht nichts:

index.js
Output
Click Run to see the output here.

Ob ein Wert als „gleich" gilt, wird nach derselben Regel wie bei === entschieden – mit einer kleinen Ausnahme: NaN gilt innerhalb eines Sets als gleich mit sich selbst, obwohl NaN === NaN sonst überall false ergibt.

Übergibst du dem Konstruktor ein Iterable, wird das Set direkt damit befüllt – und genau daher kommt auch der bekannte Trick zum Entfernen von Duplikaten aus einem Array:

index.js
Output
Click Run to see the output here.

Eine Zeile, funktioniert mit jedem primitiven Typ. Bei Arrays aus Objekten klappt das nicht — zwei verschiedene Objekte mit denselben Feldern sind immer noch zwei verschiedene Werte — aber für Strings, Zahlen und Booleans ist das die idiomatische Art, Duplikate aus einem Array zu entfernen.

Set vs. Array: Wann lohnt sich der Wechsel?

Arrays und Sets halten beide eine Sammlung von Werten — wann greift man also zu welchem?

Ein Set ist die bessere Wahl, wenn:

  • Werte eindeutig sein müssen und du willst, dass die Runtime das auch sicherstellt.
  • Du viele Zugehörigkeitsprüfungen machst. set.has(x) läuft in O(1), array.includes(x) in O(n). In einer Schleife summiert sich dieser Unterschied rasant.
  • Dir die Einfügereihenfolge reicht. Sets iterieren in Einfügereihenfolge, unterstützen aber keinen Indexzugriff.

Beim Array bleibst du, wenn:

  • Du positionalen Zugriff brauchstarr[0], Slicing, Sortieren.
  • Duplikate eine Bedeutung haben — zum Beispiel ein Warenkorb mit zweimal demselben Artikel.
  • Du viel mit Array-Methoden wie .map, .filter oder .reduce arbeitest. Sets haben die nicht; du müsstest erst per Spread in ein Array umwandeln.

Ein kurzes Beispiel, das den Performance-Unterschied zeigt:

index.js
Output
Click Run to see the output here.

Wäre banned ein Array, müsste jeder filter-Callback die komplette Liste durchsuchen. Als Set läuft jede Abfrage in konstanter Zeit.

Ein Set iterieren

Gleiches Spiel wie bei Map — for...of funktioniert direkt, und mit dem Spread-Operator bekommst du daraus ein Array:

index.js
Output
Click Run to see the output here.

Auch Sets bieten .keys(), .values() und .entries() an — analog zur Map, obwohl Keys und Values bei einem Set ja dasselbe sind. In der Praxis iterierst du meistens einfach direkt darüber.

Praxisbeispiel: Unique Visitors pro Seite zählen

Jetzt kombinieren wir beides — eine Map, die Seitenpfade auf ein Set von Visitor-IDs abbildet:

index.js
Output
Click Run to see the output here.

Die Map übernimmt das Mapping von Pfad zu Bucket, das Set kümmert sich um die Deduplizierung innerhalb jedes Buckets. Das Ganze ließe sich auch mit einem schlichten Object und Arrays umsetzen – aber dann müsstest du dich überall mit zusätzlichen indexOf-Checks und hasOwnProperty-Abfragen herumschlagen.

Kurz angerissen: WeakMap und WeakSet

Für einen sehr speziellen Anwendungsfall gibt es zwei verwandte Collections: WeakMap und WeakSet. Sie halten ihre Referenzen schwach – das heißt, ein Eintrag wird automatisch vom Garbage Collector eingesammelt, sobald es keine anderen Referenzen mehr auf den Schlüssel (bei WeakMap) bzw. auf den Wert (bei WeakSet) gibt.

index.js
Output
Click Run to see the output here.

Sie akzeptieren ausschließlich Objekte als Schlüssel, sind nicht iterierbar und besitzen kein .size. Das ist so gewollt – wären sie iterierbar, würde der Garbage Collector beobachtbar. Praktisch sind sie, wenn du Metadaten zu Objekten cachen willst, die dir nicht gehören. Im Alltag trifft man sie eher selten.

Als Nächstes: JSON

Map und Set sind im Arbeitsspeicher super, aber keines von beiden übersteht JSON.stringify unbeschadet – aus Maps wird {}, aus Sets ebenfalls {}. Auf der nächsten Seite geht es um JSON: wie du Daten serialisierst und parst, und welche Muster sich bewährt haben, um die hier vorgestellten Collections über Netzwerk- oder Dateigrenzen hinweg zu transportieren.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Map und Object in JavaScript?

Eine Map akzeptiert beliebige Werte als Schlüssel – Objekte, Funktionen, Zahlen, alles. Ein normales Object wandelt Keys dagegen immer in Strings (oder Symbols) um. Dazu kommt: Map kennt die eigene Größe über .size, iteriert garantiert in Einfügereihenfolge und erbt nichts vom Prototype – es gibt also keine Kollisionen mit toString oder constructor. Kurz gesagt: Map nehmen, wenn die Schlüssel keine Strings sind oder wenn häufig Einträge hinzukommen und wieder verschwinden.

Wofür nutzt man ein Set in JavaScript?

Ein Set speichert nur eindeutige Werte – Duplikate werden stillschweigend ignoriert. Der schnellste Weg, ein Array zu deduplizieren, ist daher [...new Set(arr)]. Außerdem bekommst du mit .has() eine Prüfung in O(1), was array.includes() in Schleifen locker abhängt.

Wie iteriere ich über eine Map?

for...of funktioniert direkt: mit for (const [key, value] of myMap) lässt sich jeder Eintrag per Destructuring auseinandernehmen. Alternativ kannst du über myMap.keys(), myMap.values() oder myMap.entries() laufen. Die Reihenfolge entspricht dabei immer der Einfügereihenfolge – etwas, das normale Objekte bei Schlüsseln, die wie Zahlen aussehen, nicht zuverlässig garantieren.

Lerne mit Coddy zu programmieren

LOS GEHT'S