`Map`-objekt

Denne artikel forklarer Map-objektet.

Vi forklarer trin for trin, fra grundlæggende operationer til praktiske eksempler, der er nyttige i virkelige scenarier.

YouTube Video

Map-objekt

Map er en samling, der gemmer nøgle-værdi-par. Det ligner et objekt, men adskiller sig ved, at enhver type, såsom objekter, funktioner eller primitive værdier, kan bruges som nøgler, og indsættelsesrækkefølgen bevares.

Grundlæggende om Map

Lad os først se på, hvordan man opretter en Map og udfører grundlæggende operationer.

Følgende kode er et minimalt eksempel, der opretter et tomt map, tilføjer nøgler og henter værdier.

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
  • I denne kode kan du tilføje elementer med set, hente værdier med get, og kontrollere antallet af elementer med size.
  • Map bevarer indsættelsesrækkefølgen, hvilket gør den velegnet til rækkefølgeafhængig behandling.

Adfærd for set, get, has og delete

Her er eksempler på typiske læse-, skrive-, eksistenskontrol- og sletteoperationer.

Med den følgende kode kan du kontrollere returværdierne og effekterne af hver metode.

 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 returnerer undefined, hvis nøglen ikke findes. has tjekker for eksistensen af en nøgle, og delete fjerner en nøgle.
  • Da set returnerer selve mappen, er metodekædning mulig.

Enhver type kan bruges som en nøgle (herunder objekter som nøgler)

En af de største fordele ved Map er, at du kan bruge objekter direkte som nøgler.

Det følgende eksempel viser, hvordan man tilknytter værdier i en Map ved brug af objekter som nøgler.

 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'
  • Når man bruger objekter som nøgler, er det vigtigt, at de er den samme reference. Selv hvis deres indhold er det samme, bliver objekter med forskellige referencer behandlet som forskellige og er ikke den samme nøgle.

Iteration (gentagelse)

Map bevarer indsættelsesrækkefølgen, så iteration bruges ofte.

Nedenfor viser vi, hvordan man bruger for...of, forEach og metoderne keys(), values() og entries().

 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() returnerer et array af [key, value]-par, som kan laves om til et array med spread-syntaksen. Bemærk, at callback'en for forEach modtager argumenterne i rækkefølgen value, key.

Konvertering mellem Map og Object

Du kan konvertere et eksisterende objekt til en Map, eller konvertere en Map til et simpelt objekt eller 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]]
  • Ved at bruge Object.entries og Object.fromEntries er konvertering let. Da objekt-nøgler er begrænset til strenge eller symboler, går ikke-strengede nøgler tabt, når man konverterer tilbage til et objekt.

Praktisk mønster: Tælling af hyppighed (Count Map)

Når du tæller hyppigheden af elementer i et array, gør brugen af et Map processen enklere.

Den følgende kode er et eksempel på at bruge en map til at tælle hyppigheden af strenge i et array og sortere dem.

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]]
  • Ved at bruge en Map kan du nemt kontrollere eksistens og opdatere værdier. Dette kan også gøres med objekter, men Map kan være mere intuitiv, når man arbejder med vilkårlige nøgler.

Bemærkninger om Map og JSON.stringify (serialisering)

JSON.stringify kan ikke serialisere en Map direkte. Hvis du skal gemme en Map, skal du først konvertere den.

Følgende eksempel viser, hvordan man konverterer en Map til et array, før den omdannes til JSON, og hvordan man gendanner den igen.

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, der skal gemmes eller overføres, bør konverteres til arrays, før de serialiseres. Når du gendanner, skal du bruge JSON.parse til at omdanne det til et array og derefter lave det tilbage til en Map.

Introduktion til WeakMap og hvordan man bruger det

WeakMap adskiller sig ved, at dets nøgler er svagt refererede (underlagt garbage collection).

Den er nyttig til at holde cache eller metadata, hvor objekter bruges som nøgler, og de frigøres automatisk, når nøgle-objektet bliver samlet op (garbage collected).

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 ikke gennemløbes eller få kontrolleret sin størrelse, men er nyttig for at undgå memory leaks.

Sammendrag

Map er en praktisk samling, der, i modsætning til objekter, tillader enhver type som nøgle og bevarer indsættelsesrækkefølgen. Ved at forstå alt fra grundlæggende operationer til avanceret brug kan du håndtere data mere fleksibelt og intuitivt. Ved at bruge Object og Map korrekt i forhold til brugstilfældet kan du forbedre kodens klarhed og læsbarhed betydeligt.

Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.

YouTube Video