Mapy a obiekty w ES6, kiedy używać?


83

Odniesienie: Mapy MDN

Używaj map na obiektach, gdy klucze są nieznane do czasu wykonania oraz gdy wszystkie klucze są tego samego typu i wszystkie wartości są tego samego typu.

Używaj obiektów, gdy istnieje logika działająca na poszczególnych elementach.

Pytanie:

Jaki jest odpowiedni przykład użycia Map nad obiektami? w szczególności „kiedy klucze byłyby nieznane do czasu wykonania?”

var myMap = new Map();

var keyObj = {},
    keyFunc = function () { return 'hey'},
    keyString = "a string";

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");

console.log(myMap.get(keyFunc));

Tak, zauważyłem to. Gdy ustawiam funkcję jako wartość. @JonathanLonowski czy możesz pomyśleć o tym, kiedy powinienem to zrobić :( trudno jest myśleć o przypadkach.
Matthew Harwood

7
Możesz go użyć, jeśli powiesz element DOM, z którym chcesz powiązać niektóre dane za pomocą obiektu. Zamiast używać, powiedzmy, identyfikatora elementu jako klucza w obiekcie, możesz użyć samego elementu jako klucza w Mapie, więc nie obchodzi Cię, czy element ma identyfikator (lub jakikolwiek inny unikatowy identyfikator inny niż odwołanie do obiektu ) albo nie.
RobG,

1
@RobG tylko mały dodatek: w takim przypadku WeakMapmoże to być również pomocne.
zerkms

1
Myślę, że sugeruje to użycie obiektów jako / dla rekordów i Map dla każdego innego rodzaju mapowania. Przez rekordy mam na myśli strukturę danych ze stałym zestawem pól, taką jak obiekt użytkownika, który ma pola namei idna przykład.
Felix Kling

1
Kiedy czytałem tę stronę MDN, lista przypadków użycia była dużo bardziej pomocna niż cytowany przez ciebie akapit. Na pewno w odniesieniu do pytania postawionego w twoim tytule.
CodingIntrigue,

Odpowiedzi:


51

Jaki jest odpowiedni przykład użycia Map nad obiektami?

Myślę, że podałeś już jeden dobry przykład: musisz przynajmniej użyć Maps, kiedy używasz obiektów (w tym obiektów Function) jako kluczy.

w szczególności „kiedy klucze byłyby nieznane do czasu wykonania?”

Zawsze, gdy nie są znane w czasie kompilacji. Krótko mówiąc, zawsze powinieneś używać a, Mapgdy potrzebujesz kolekcji klucz-wartość . Dobrym wskaźnikiem, że potrzebujesz kolekcji, jest dynamiczne dodawanie i usuwanie wartości z kolekcji, a zwłaszcza gdy nie znasz tych wartości wcześniej (np. Są odczytywane z bazy danych, wprowadzane przez użytkownika itp.).

Z kolei obiektów należy używać, gdy wiadomo, jakie i ile właściwości ma obiekt podczas pisania kodu - gdy ich kształt jest statyczny. Jak to ujął @Felix: kiedy potrzebujesz rekordu . Dobrym wskaźnikiem potrzeby jest to, że pola mają różne typy i kiedy nigdy nie musisz używać notacji w nawiasach (lub spodziewasz się ograniczonego zestawu nazw właściwości).


1
Lub z innego punktu widzenia: gdy potrzebujesz iterować po właściwościach swojego obiektu na poziomie danych (np. for..of) Zamiast na poziomie programu (np. for..in) Użyj Map. Więcej informacji na temat tych warunków w tej odpowiedzi .

Jako komentarz dodam również fakt, że za każdym razem, gdy nie wiesz, jakiego typu będzie twój klucz i nie oczekujesz stringów jako kluczowych typów danych, użyj map stackoverflow.com/questions/32600157/ ...
Carmine Tambascia

26

Myślę, że z ES2015 Mappozostały tylko dwa powody, aby używać zwykłych obiektów:

  • Nie chcesz w ogóle iterować po właściwościach typu obiektu
  • lub robisz, ale kolejność właściwości nie ma znaczenia i podczas iteracji możesz odróżnić program od poziomu danych

Kiedy porządek nieruchomości nie ma znaczenia?

  • jeśli masz tylko jedną wartość i niektóre funkcje, które powinny być z nią jawnie powiązane (np. Promise- który jest proxy dla przyszłej wartości - i then/ catch)
  • jeśli masz strukturę danych podobną do struktury / rekordu ze statycznym zestawem właściwości znanym w „czasie kompilacji” (zwykle struktury / rekordy nie są iterowalne)

We wszystkich innych przypadkach możesz rozważyć użycie Map, ponieważ zachowuje porządek właściwości i oddziela program (wszystkie właściwości przypisane do Mapobiektu) od poziomu danych (wszystkie wpisy w nim Mapsamym).

Jakie są wady Map?

  • tracisz zwięzłą składnię literału obiektowego
  • potrzebujesz niestandardowych zamienników dla JSON.stringyfy
  • tracisz destrukturyzację, która i tak jest bardziej przydatna w przypadku statycznych struktur danych

Ta kwestia bardzo mnie niepokoi: „prawdopodobnie jest wolniejsza niż czyste obiekty podobne do hasmapy”. Pomyślałem o zastąpieniu wszystkich obiektów mapami ze względu na poprawę wydajności. Ale mówisz, że jest wolniej ...
mesqueeb

1
Masz rację. Mapjest prawdopodobnie szybszy, ponieważ opiera się wyłącznie na mieszaniu, ale Objectjest nieco bardziej skomplikowany. Dzięki!

11

Używaj map na obiektach, gdy klucze są nieznane do czasu wykonania oraz gdy wszystkie klucze są tego samego typu i wszystkie wartości są tego samego typu.

Nie mam pojęcia, dlaczego ktoś napisałby coś tak ewidentnie błędnego. Muszę powiedzieć, że w dzisiejszych czasach ludzie znajdują coraz więcej błędnych i / lub wątpliwych treści na MDN.

Nic w tym zdaniu nie jest poprawne. Głównym powodem używania map jest potrzeba kluczy z wartościami obiektowymi. Pomysł, że wartości powinny być tego samego typu, jest absurdalny - choć oczywiście mogą być. Pomysł, że nie powinno się używać obiektów, gdy klucze są nieznane do czasu wykonania, jest równie absurdalny.


1
Nie rozumiem, co jest takiego absurdalnego w tym pomyśle? Kiedy potrzebujesz kolekcji, zazwyczaj są one ściśle wpisywane na maszynie (oczywiście mogą istnieć wyjątki). Myślę też, że zaprzestanie używania obiektów do kolekcji (jeśli Mapsą dostępne) to dobra rada.
Bergi

To, że zbiory są zazwyczaj ściśle wpisane na maszynie, jest logicznie różne od stwierdzenia, że ​​coś ściśle wpisanego powinno być zbiorem.

1
Tak, myślę, że to trochę dziwne, ale pomysł jest w porządku. Wydaje mi się, że myśleli, że „klucze są nieznane do czasu uruchomienia” już tworzą kolekcję. Masz pomysł na lepsze sformułowanie?
Bergi

1
Zgoda. MDN ma bardzo dobrą dokumentację, ale powinni trzymać się dokumentowania dokumentacji API i nie próbować udzielać porad programistycznych.
AlexG

5

Jedną z różnic między Mapi Objectjest:

Mapmoże używać złożonego typu danych jako klucza. lubię to:

const fn = function() {}
const m = new Map([[document.body, 'stackoverflow'], [fn, 'redis']]);

m.get(document.body) // 'stackoverflow'
m.get(fn) //'redis'

uwaga: w przypadku złożonego typu danych, jeśli chcesz uzyskać wartość, musisz przekazać to samo odwołanie co klucz.

Object, jako klucz przyjmuje tylko prosty typ danych ( number, string).

const a = {};
a[document.body] = 'stackoverflow';

console.log(a) //{[object HTMLBodyElement]: "stackoverflow"}

3

Objects są podobne do Maps w tym sensie, że oba umożliwiają ustawianie kluczy na wartości, pobieranie tych wartości, usuwanie kluczy i wykrywanie, czy coś jest przechowywane w kluczu. Z tego powodu (i ponieważ nie było wbudowanych alternatyw), Objects były używane jako Maps w przeszłości; jednak istnieją istotne różnice, które sprawiają, że Mapw niektórych przypadkach preferowane jest użycie :

  • Klucze a Objectto Strings i Symbols, podczas gdy mogą to być dowolne wartości a Map, w tym funkcje, obiekty i dowolny prymityw.
  • Klucze w Mapsą uporządkowane, a klucze dodane do obiektu nie. Tak więc podczas iteracji Mapobiekt zwraca klucze w kolejności wstawiania.
  • Możesz łatwo uzyskać rozmiar nieruchomości Mapza pomocą sizewłaściwości, podczas gdy liczbę nieruchomości w jednym Objectnależy określić ręcznie.
  • A Mapjest iterowalny i dlatego może być bezpośrednio iterowany, podczas gdy iterowanie po nim Objectwymaga uzyskania jego kluczy w pewien sposób i iteracji po nich.
  • An Objectma prototyp, więc na mapie znajdują się domyślne klucze, które mogą kolidować z twoimi kluczami, jeśli nie będziesz ostrożny. Od wersji ES5 można to ominąć za pomocą map = Object.create(null), ale rzadko się to robi.
  • A Mapmoże działać lepiej w scenariuszach obejmujących częste dodawanie i usuwanie par kluczy.

MDN


2

To pytanie jest duplikatem ale dopóki nie zostanie zamknięty, oto moja odpowiedź stamtąd :

Oprócz innych odpowiedzi odkryłem, że Mapy są bardziej nieporęczne i bardziej szczegółowe w obsłudze niż obiekty.

obj[key] += x
// vs.
map.set(map.get(key) + x)

Jest to ważne, ponieważ krótszy kod jest szybszy do odczytania, bardziej bezpośrednio wyrazisty i lepiej trzymany w głowie programisty .

Kolejny aspekt: ​​ponieważ set () zwraca mapę, a nie wartość, nie można łączyć przypisań w łańcuch.

foo = obj[key] = x;  // Does what you expect
foo = map.set(key, x)  // foo !== x; foo === map

Debugowanie map jest również bardziej bolesne. Poniżej nie możesz właściwie zobaczyć, jakie klucze znajdują się na mapie. Aby to zrobić, musiałbyś napisać kod.

Powodzenia w ocenie iteratora mapy

Obiekty mogą być oceniane przez dowolne IDE:

WebStorm oceniający obiekt


7
To w ogóle nie odpowiada na pytanie „ Jaki jest odpowiedni przykład użycia Map na obiektach?
Bergi

6
Nie zamieszczaj swoich odpowiedzi w innych miejscach. I nie, pytanie nie jest powtórzeniem.
Bergi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.