Czy jest jakiś moment w używaniu ES6 Map, gdy wszystkie klucze są ciągami znaków?

36

Klucze obiektu zwykłego muszą być łańcuchami, a Mapklucz może zawierać klucze dowolnego typu.

Ale w praktyce mam z tego niewiele pożytku. W prawie wszystkich przypadkach używam ciągów jako kluczy. I prawdopodobnie new Map()jest wolniejszy niż {}. Czy jest więc jakiś inny powód, dla którego lepiej byłoby użyć Mapzamiast zwykłego obiektu?

kalus
źródło
3
MDN , jak zwykle, ma dobre porównanie.
Chris Hayes
1
Do Twojej wiadomości, Mapa wydaje się być szybsza zarówno w ustawieniach, jak i uzyskiwaniu.
mpen
@mpen - jsperf jest teraz wyłączony. Czy na pewno map.set('foo', 123)wykonujesz szybciej niż obj.foo = 123? Jeśli tak, to bardzo zaskakujące
callum
@callum Uhh .. nie, nie pozytywne. Możesz napisać kilka nowych testów wydajności.
mpen

Odpowiedzi:

42

Istnieje kilka powodów, dla których wolę używać Maps niż zwykłych obiektów ( {}) do przechowywania danych środowiska wykonawczego (pamięci podręcznych itp.):

  1. Ta .sizewłaściwość informuje mnie, ile wpisów istnieje na tej mapie;
  2. Różne metody narzędzie - .clear(), .forEach()itp;
  3. Domyślnie zapewniają mi iteratory!

Co drugi przypadek, taki jak przekazywanie argumentów funkcji, przechowywanie konfiguracji itp., Wszystkie są zapisywane przy użyciu prostych obiektów.

Pamiętaj też: nie próbuj zbyt wcześnie optymalizować kodu. Nie trać czasu na porównywanie prostych obiektów z mapami, chyba że w projekcie występują problemy z wydajnością.

gustavohenke
źródło
1
Jaka funkcja hashcode tożsamości jest używana przez Javascript?
Pacerier
1
@Pacerier ===:)
gustavohenke
Mapy są obecnie znacznie szybsze niż zwykłe obiekty.
jayarjo
@gustavohenke To nieprawda. Mapużywa algorytmu SameValueZero. developer.mozilla.org/en-US/docs/Web/JavaScript/…
lolmaus - Andrey Mikhaylov
@ lolmaus-AndreyMikhaylov w porządku, ale czy mówiłem coś o Mapużywaniu tego czy tamtego?
gustavohenke
4

Nie jestem tego pewien, ale myślę, że wydajność NIE jest powodem do korzystania z Map. Spójrz na tę zaktualizowaną stronę jsperf:

http://jsperf.com/es6-map-vs-object-properties/73

Wygląda na to, że (przynajmniej w przypadku łańcuchów) obiekty są znacznie szybsze niż mapy do podstawowego ustawiania i pobierania.

starlogodaniel
źródło
2
Nie tak piszesz testy wydajności.
Qix,
6
Nie tak piszesz przydatne komentarze. Jeśli masz alternatywną metodologię, możesz ją rozwinąć. Co konkretnie jest nie tak z tym, jak zostały napisane te testy? Czy są w jakikolwiek sposób nieważne lub nieprzydatne?
starlogodaniel
9
Semantyka / konstrukcje językowe testowane za pomocą mikrodruków mogą różnić się tylko jedną zmienną. Twoje testy różnią się w zależności od liczby iteracji, a kilka z nich zoptymalizuje zawartość wewnętrznej pętli, ponieważ wynik nie jest używany. Niektóre testy wstępnie deklarują zmienne, podczas gdy inne mają deklarację zmiennych zgodną z pętlą for - co może powodować różne nieprawidłowości w wydajności.
Qix,
1
Och, masz absolutną rację. W mojej obronie moja wersja była ulepszona w stosunku do poprzedniej, ale brakowało mi zarówno optymalizacji przed deklaracją, jak i wewnętrznej pętli. Pracowałem z kolegą, który poprawił mój projekt i myślę, że rozwiązałem te problemy: jsperf.com/es6-map-vs-object-properties/88 . Myślę jednak, że poprawne są różne style pętli dla różnych struktur danych; w rzeczywistym użyciu ludzie wybierają strukturę pętli o najlepszej wydajności, a mapa i obiekt mają różne „optymalne” struktury pętli. W każdym razie dzięki za haczyk.
starlogodaniel
Ok, rozumiem teraz - były one wolniejsze niż zwykłe obiekty, ale zostały znacznie zoptymalizowane w najnowszych przeglądarkach.
jayarjo
0

Pozostałe odpowiedzi nie wspominają o ostatniej różnicy między obiektami a Maps:

MapObiekt posiada par klucz-wartość i zapamiętuje oryginalną kolejność wkładania kluczy .

Zatem podczas iteracji nad nim obiekt Map zwraca klucze w kolejności wstawiania.

Cytat z MDN , moje podkreślenie


To był główny powód, dla którego zdecydowałem się wykorzystać Mappo raz pierwszy w ostatnim projekcie. Miałem normalny obiekt, który musiałem wyświetlić w <table>, a każda właściwość znajdowała się w określonym rzędzie.

let productPropertyOrder = [ "name", "weight", "price", "stocked" ];

let product =
{
    name: "Lasagne",
    weight: "1kg",
    price: 10,
    stocked: true
}

Napisałem funkcję przekształcania obiektu w Mapodpowiedni klucz według kolejności:

function objectToMap( obj, order )
{
    let map = new Map();

    for ( const key of order )
    {
        if ( obj.hasOwnProperty( key ) )
        {
            map.set( key, obj[ key ] );
        }
    }

    return map;
}

Następnie mapę można iterować w żądanej kolejności:

let productMap = objectToMap( product, productPropertyOrder );

for ( const value of productMap.values() )
{
    let cell = document.createElement( "td" );
    cell.innerText = value;
    row.appendChild( cell );
}

Oczywiście jest to nieco wymyślone, ponieważ równie dobrze można wyświetlać podczas iteracji po porządku właściwości bez tworzenia Mapw tym procesie:

for ( const key of productPropertyOrder )
{
    if ( product.hasOwnProperty( key ) )
    {
        let value = product[ key ];
        // create cell
    }
}

Ale jeśli masz szereg takich obiektów i zamierzasz wyświetlać je w wielu miejscach, to najpierw warto je przekonwertować na mapy.

WD40
źródło