Het `Map`-object

Dit artikel legt het Map-object uit.

We leggen stap voor stap uit, van basisbewerkingen tot praktische voorbeelden die nuttig zijn in echte situaties.

YouTube Video

Het Map-object

Map is een collectie die sleutel-waardeparen opslaat. Het lijkt op een object, maar verschilt doordat elk type, zoals objecten, functies of primitieve waarden, als sleutel kan worden gebruikt en de invoegvolgorde behouden blijft.

Basisprincipes van Map

Laten we eerst kijken hoe je een Map aanmaakt en basisbewerkingen uitvoert.

De volgende code is een minimaal voorbeeld dat een lege map aanmaakt, sleutels toevoegt en waarden ophaalt.

1// Create an empty Map and add key-value pairs
2const m = new Map();
3m.set('a', 1);
4m.set('b', 2);
5
6console.log(m.get('a')); // 1
7console.log(m.size);     // 2
  • In deze code kun je elementen toevoegen met set, waarden ophalen met get en het aantal elementen controleren met size.
  • Map behoudt de invoegvolgorde, wat het geschikt maakt voor volgordeafhankelijke verwerking.

Gedrag van set, get, has en delete

Hier zijn voorbeelden van typische lees-, schrijf-, bestaanscontrole- en verwijderbewerkingen.

Met de onderstaande code kun je de retourwaarden en effecten van elke methode controleren.

 1// Demonstrate set, get, has, and delete
 2const m2 = new Map();
 3m2.set('x', 10);
 4console.log(m2.has('x'));  // true
 5console.log(m2.get('y'));  // undefined
 6
 7m2.delete('x');
 8console.log(m2.has('x'));  // false
 9
10// set returns the map itself, allowing method chaining
11m2.set('a', 1).set('b', 2);
12console.log(m2);  // Map { 'a' => 1, 'b' => 2 }
  • get retourneert undefined als de sleutel niet bestaat. has controleert of een sleutel bestaat, en delete verwijdert een sleutel.
  • Aangezien set de map zelf retourneert, is method chaining mogelijk.

Elk type kan als sleutel worden gebruikt (objecten als sleutels gebruiken)

Een van de grootste voordelen van Map is dat je objecten direct als sleutel kunt gebruiken.

Het volgende voorbeeld laat zien hoe je waarden in een Map koppelt met objecten als sleutels.

 1// Use objects as keys in a Map
 2const keyObj = { id: 1 };
 3const keyFunc = () => {};
 4const objMap = new Map();
 5
 6// Another object with the same content but a different reference
 7const anotherKeyObj = { id: 1 };
 8
 9objMap.set(keyObj, 'objectValue');
10objMap.set(keyFunc, 'functionValue');
11objMap.set(anotherKeyObj, 'anotherValue');
12
13console.log(objMap.get(keyObj));         // 'objectValue'
14console.log(objMap.get(keyFunc));        // 'functionValue'
15console.log(objMap.get(anotherKeyObj));  // 'anotherValue'
  • Als je objecten als sleutel gebruikt, is het belangrijk dat ze dezelfde referentie zijn. Zelfs als hun inhoud hetzelfde is, worden objecten met verschillende referenties als verschillend beschouwd en zijn het niet dezelfde sleutel.

Iteratie (lussen)

Map behoudt de invoegvolgorde, dus iteratie wordt vaak gebruikt.

Hieronder laten we zien hoe je for...of, forEach en de methoden keys(), values() en entries() gebruikt.

 1// Iterating a Map with for...of and forEach
 2const iterMap = new Map([['a', 1], ['b', 2], ['c', 3]]);
 3
 4// for...of over entries (default)
 5for (const [key, value] of iterMap) {
 6  console.log(key, value);
 7}
 8
 9// forEach callback
10iterMap.forEach((value, key) => {
11  console.log(key, value);
12});
13
14// keys() and values()
15console.log([...iterMap.keys()]);   // ['a','b','c']
16console.log([...iterMap.values()]); // [1,2,3]
  • entries() retourneert een array van [key, value] paren, die met de spread-syntax in een gewone array kunnen worden omgezet. Let op dat de callback van forEach argumenten ontvangt in de volgorde value, key.

Conversie tussen Map en Object

Je kunt een bestaand object omzetten naar een Map, of een Map omzetten naar een gewoon object of een array.

 1// Convert between Map and Object / Array
 2const obj = { a: 1, b: 2 };
 3const mapFromObj = new Map(Object.entries(obj)); // Object -> Map
 4console.log(mapFromObj.get('a')); // 1
 5
 6const objFromMap = Object.fromEntries(mapFromObj); // Map -> Object
 7console.log(objFromMap); // { a: 1, b: 2 }
 8
 9const arrayFromMap = [...mapFromObj]; // Map -> Array of [key, value]
10console.log(arrayFromMap); // [['a',1], ['b',2]]
  • Het gebruik van Object.entries en Object.fromEntries maakt conversie eenvoudig. Aangezien object-sleutels beperkt zijn tot strings of symbolen, gaan niet-string-sleutels verloren bij het terugconverseren naar een object.

Praktisch patroon: Frequentietelling (tellingen met Map)

Bij het tellen van de frequentie van elementen in een array maakt het gebruik van een Map het proces eenvoudiger.

De onderstaande code is een voorbeeld waarin een map wordt gebruikt om de frequenties van strings in een array te tellen en te sorteren.

1// Count frequencies with Map
2const arr = ['apple','banana','apple','orange','banana','apple'];
3const freq = new Map();
4
5for (const item of arr) {
6  freq.set(item, (freq.get(item) || 0) + 1);
7}
8
9console.log([...freq.entries()]); // [['apple',3], ['banana',2], ['orange',1]]
  • Met een Map kun je eenvoudig controleren of iets bestaat en bijwerken. Dit kan ook met objecten gedaan worden, maar Map is vaak intuïtiever wanneer je met willekeurige sleutels werkt.

Opmerkingen over Map en JSON.stringify (serialisatie)

JSON.stringify kan een Map niet direct serialiseren. Als je een Map wilt opslaan, moet je deze eerst omzetten.

Het volgende voorbeeld laat zien hoe je een Map omzet naar een array voordat je het naar JSON converteert, en hoe je het weer herstelt.

1// Serialize and deserialize a Map
2const m3 = new Map([['x', 1], ['y', 2]]);
3const json = JSON.stringify([...m3]); // convert to array first
4console.log(json); // '[["x",1],["y",2]]'
5
6const restored = new Map(JSON.parse(json));
7console.log(restored.get('x')); // 1
  • Maps die opgeslagen of verzonden moeten worden, moeten eerst worden omgezet naar arrays voordat ze geserialiseerd worden. Gebruik bij het herstellen JSON.parse om het naar een array om te zetten, en zet het dan weer om in een Map.

Introductie tot WeakMap en hoe het te gebruiken

WeakMap verschilt doordat de sleutels zwak worden gerefereerd (onderhevig aan garbage collection).

Het is handig voor het bijhouden van cache of metadata met objecten als sleutels, die automatisch vrijkomen wanneer het sleutelobject wordt opgeruimd.

1// WeakMap for metadata tied to object lifecycle
2const wm = new WeakMap();
3let obj = {};
4wm.set(obj, { meta: 'info' });
5console.log(wm.get(obj)); // { meta: 'info' }
6
7obj = null; // now the object can be GC'd and its entry removed from WeakMap
  • WeakMap kan niet worden doorlopen of de grootte kan niet worden gecontroleerd, maar is handig om geheugengebrek te voorkomen.

Samenvatting

Map is een handige collectie die, anders dan objecten, elk type als sleutel toestaat en de invoegvolgorde behoudt. Door alles van de basisbewerkingen tot het geavanceerd gebruik te begrijpen, kun je data flexibeler en intuïtiever beheren. Door Object en Map op de juiste manier te gebruiken, afhankelijk van de situatie, kun je de duidelijkheid en leesbaarheid van je code sterk verbeteren.

Je kunt het bovenstaande artikel volgen met Visual Studio Code op ons YouTube-kanaal. Bekijk ook het YouTube-kanaal.

YouTube Video