Obiekt Map w JavaScripcie: metody, iteracja i WeakMap

Obiekt Map w JavaScripcie: metody, iteracja i WeakMap

Map to konstruktor, który w wielu sytuacjach daje prostszy i wydajniejszy sposób na uporządkowanie danych i sięganie po nie. 

Oto w trzech punktach, co konkretnie robi obiekt Map:

  • Map przechowuje pary klucz-wartość, w których klucz może być dowolnego typu.

  • Map pamięta pierwotną kolejność wstawiania kluczy.

  • Map ma właściwość, która zwraca jego rozmiar.

Przydatne metody obiektu Map w JavaScripcie

  • clear() – usuwa wszystkie elementy obiektu map.
  •  delete(key) – usuwa element wskazany kluczem. Zwraca true, jeśli element był w obiekcie Map, i false, jeśli go tam nie było.
  •  entries() – zwraca nowy obiekt Iterator zawierający tablicę [key, value] dla każdego elementu obiektu map. Kolejność wpisów w obiekcie Map to kolejność ich wstawiania.
  •  forEach(callback[, thisArg]) – wywołuje callback dla każdej pary klucz-wartość w Map, w kolejności wstawiania. Opcjonalny parametr thisArg ustawia wartość this dla każdego wywołania.
  •  get(key) – zwraca wartość powiązaną z kluczem. Jeśli klucz nie istnieje, zwraca undefined.
  •  has(key) – zwraca true, jeśli wartość powiązana z kluczem istnieje, a w przeciwnym razie false.
  •  keys() –  zwraca nowy Iterator zawierający klucze elementów w kolejności wstawiania.
  •  set(key, value) – ustawia wartość klucza w obiekcie map. Zwraca sam obiekt map, więc tę metodę da się łączyć w łańcuch z innymi.
  •  values() zwraca nowy obiekt iteratora zawierający wartość każdego elementu w kolejności wstawiania.

Przykłady zastosowań obiektu Map w JavaScripcie

Tworzenie nowego obiektu Map

Załóżmy, że masz taką listę obiektów użytkowników:

javascript
let pierre = {name: 'Pierre Lepez'},
    jean = {name: 'Jean Doe'},
    kevin = {name: 'Kévin Gomez'};

Załóżmy dalej, że potrzebujesz obiektu Map z użytkownikami i ich rolami. Wystarczy do tego taki kod:

javascript
let userRoles = new Map();

userRoles jest instancją obiektu Map, a jego typem jest object, co pokazuje poniższy przykład:

javascript
console.log(typeof(userRoles)); // object
console.log(userRoles instanceof Map); // true

Dodawanie elementów do Map

Żeby przypisać użytkownikowi rolę, użyj metody set():

javascript
userRoles.set(kevin, 'admin');

Metoda set() wiąże użytkownika kevin z rolą admin. Ponieważ set() da się łączyć w łańcuch, możesz zaoszczędzić sobie pisania, jak w tym przykładzie:

javascript
userRoles.set(pierre, 'éditeur')
          .set(jean, 'abonné');

Inicjalizacja obiektu Map obiektem iterowalnym

Jak już wspomniałem, konstruktorowi Map() możesz przekazać obiekt iterowalny:

javascript
let userRoles = new Map([
    [kevin, 'admin'],
    [pierre, 'éditeur'],
    [jean, 'abonné']
]);

Pobieranie elementu po kluczu

Jeśli chcesz sprawdzić rolę Kévina, użyj metody get():

javascript
userRoles.get(kevin); // admin

Jeśli podasz klucz, który nie istnieje, metoda get() zwróci undefined.

javascript
let foo = {name: 'Foo'};
userRoles.get(foo); //undefined

Sprawdzanie, czy element o danym kluczu istnieje

Żeby sprawdzić, czy klucz jest w naszym obiekcie Map, użyj metody has().

javascript
userRoles.has(foo); // false
userRoles.has(pierre); // true

Liczba elementów w naszym obiekcie Map

Właściwość size zwraca liczbę wpisów w obiekcie Map.

javascript
console.log(userRoles.size); // 3

Iterowanie po „kluczach” obiektu Map

Żeby pobrać klucze obiektu Map, użyj metody keys(). Metoda keys() zwraca nowy obiekt iteratora zawierający klucze elementów tego obiektu.

Poniższy przykład wypisuje nazwy użytkowników z obiektu map userRoles.

javascript
let kevin = { name: 'Kévin Feige' },
  pierre = { name: 'Pierre Rocher' },
  jean = { name: 'Jean Moulin' };

let userRoles = new Map([
    [kevin, 'admin'],
    [pierre, 'éditeur'],
    [jean, 'abonné']
]);

for (const user of userRoles.keys()) {
  console.log(user.name);
}

Wynik:

javascript
Kévin Feige
Pierre Rocher
Jean Moulin

Iterowanie po wartościach obiektu Map

Analogicznie możesz sięgnąć po metodę values(), żeby dostać obiekt iteratora z wartościami wszystkich elementów obiektu Map:

javascript
let kevin = { name: 'Kévin Feige' },
  pierre = { name: 'Pierre Rocher' },
  jean = { name: 'Jean Moulin' };

let userRoles = new Map([
    [kevin, 'admin'],
    [pierre, 'éditeur'],
    [jean, 'abonné']
]);

for (const role of userRoles.values()) {
  console.log(role);
}

Wynik:

javascript
admin
éditeur
abonné

Iterowanie po wpisach obiektu Map

Metoda entries() zwraca z kolei obiekt iteratora zawierający tablicę [key,value] dla każdego elementu obiektu Map:

javascript
let kevin = { name: 'Kévin Feige' },
  pierre = { name: 'Pierre Rocher' },
  jean = { name: 'Jean Moulin' };

let userRoles = new Map([
    [kevin, 'admin'],
    [pierre, 'éditeur'],
    [jean, 'abonné']
]);

for (const role of userRoles.entries()) {
  console.log(`${role[0].name}: ${role[1]}`);
}

Żeby pętla czytała się naturalniej, możesz użyć destrukturyzacji:

javascript
let kevin = { name: 'Kévin Feige' },
  pierre = { name: 'Pierre Rocher' },
  jean = { name: 'Jean Moulin' };

let userRoles = new Map([
    [kevin, 'admin'],
    [pierre, 'éditeur'],
    [jean, 'abonné']
]);

userRoles.forEach((role, user) => console.log(`${user.name}: ${role}`));

Poza pętlą for…of masz do dyspozycji metodę forEach() obiektu map:

Zamiana kluczy lub wartości Map na tablicę

Czasem wygodniej pracuje się na tablicy niż na obiekcie iterowalnym, wtedy przydaje się operator spread.

Poniższy przykład zamienia klucze wszystkich elementów w tablicę kluczy:

javascript
var keys = [...userRoles.keys()];
console.log(keys);

Wynik:

javascript
[ { name: 'Kévin Feige' },
  { name: 'Pierre Rocher' },
  { name: 'Jean Moulin' } ]

A ten zamienia wartości elementów w tablicę:

javascript
let roles = [...userRoles.values()];
console.log(roles);

Wynik:

javascript
[ 'admin', 'éditeur', 'abonné' ]

Usuwanie elementu po kluczu

Żeby usunąć wpis z obiektu Map, użyj metody delete().

javascript
userRoles.delete(pierre);

Usuwanie wszystkich elementów obiektu Map

Żeby usunąć wszystkie wpisy z obiektu Map, użyj metody clear():

javascript
userRoles.clear();
console.log(userRoles.size); // 0

WeakMap

WeakMap przypomina Map z jedną różnicą: klucze WeakMap muszą być obiektami. Oznacza to, że kiedy referencja do klucza (czyli do obiektu) wychodzi poza zasięg, powiązana z nim wartość jest automatycznie zwalniana z pamięci.

WeakMap ma tylko część metod obiektu Map:

  • get(key)
  • set(key, value)
  • has(key)
  • delete(key)

Oto główne różnice między Map a WeakMap:

  • Po elementach WeakMap nie da się iterować.
  • Nie da się wyczyścić wszystkich elementów naraz.
  • Nie da się sprawdzić rozmiaru WeakMap.

W tym tutorialu poznałeś obiekt Map w JavaScripcie i metody, które ułatwiają pracę z jego wpisami.

JavaScript

Damien Flandrin Web developer od 2010 roku, twórca Gekkode i Email Impact. Każdy artykuł jest sprawdzany na prawdziwym projekcie przed publikacją. Kontakt
Newsletter

Nowe testy, poradniki i projekty — e-mailem.

Powtarzalne testy, wersjonowany kod, datowane wyniki. Nigdy spamu.