Jeśli utworzę taki obiekt:
var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
Czy wynikowy obiekt zawsze będzie tak wyglądał?
{ prop1 : "Foo", prop2 : "Bar" }
Czy właściwości będą w tej samej kolejności, w której je dodałem?
javascript
object
łagodny
źródło
źródło
for-in
,Object.keys
) nie muszą go obsługiwać (oficjalnie), ale teraz jest zamówienie. (Nieoficjalnie: Firefox, Chrome i Edge zachowują określoną kolejność nawet w for-in i Object.keys, gdzie oficjalnie nie są wymagane: jsfiddle.net/arhbn3k2/1 )Odpowiedzi:
Kolejność iteracji obiektów jest zgodna z pewnym zestawem reguł od ES2015, ale nie (zawsze) jest zgodna z kolejnością wstawiania . Mówiąc najprościej, kolejność iteracji jest kombinacją kolejności wstawiania kluczy ciągów i porządku rosnącego dla kluczy podobnych do liczb:
Użycie tablicy lub
Map
obiektu może być lepszym sposobem na osiągnięcie tego.Map
dzieli pewne podobieństwaObject
i gwarantuje, że klucze będą iterowane w kolejności wstawiania , bez wyjątku:Uwaga: kolejność właściwości w obiektach nie była w ogóle gwarantowana przed ES2015. Definicja obiektu z ECMAScript wydanie trzecie (pdf) :
źródło
TAK (dla kluczy niecałkowitych).
Większość przeglądarek iteruje właściwości obiektu jako:
Niektóre starsze przeglądarki łączą kategorie 1 i 2, iterując wszystkie klucze w kolejności wstawiania. Jeśli twoje klucze mogą być analizowane jako liczby całkowite, najlepiej nie polegać na żadnej określonej kolejności iteracji.
Bieżąca specyfikacja języka (od ES2015) jest zachowywana, z wyjątkiem kluczy analizowanych jako liczby całkowite (np. „7” lub „99”), w których zachowanie jest różne w różnych przeglądarkach. Na przykład Chrome / V8 nie przestrzega kolejności wstawiania, gdy klucze są analizowane jako numeryczne.
Specyfikacja w starym języku (przed ES2015) : Kolejność iteracji była technicznie niezdefiniowana, ale wszystkie główne przeglądarki były zgodne z zachowaniem ES2015.
Należy zauważyć, że zachowanie ES2015 było dobrym przykładem specyfikacji języka opartej na istniejącym zachowaniu, a nie odwrotnie. Aby lepiej zrozumieć sposób myślenia o zgodności wstecznej, zobacz http://code.google.com/p/v8/issues/detail?id=164 , błąd Chrome, który szczegółowo omawia decyzje projektowe dotyczące zachowania kolejności iteracji w Chrome . Według jednego (raczej upartego) komentarza do tego raportu o błędzie:
źródło
createFragment
API już polega na tym ... 🤔Kolejność właściwości w normalnych obiektach jest złożonym tematem w Javascript.
Podczas gdy w ES5 wyraźnie nie określono kolejności, w niektórych przypadkach ES2015 ma zamówienie. Podany jest następujący obiekt:
Powoduje to następującą kolejność (w niektórych przypadkach):
Istnieją zatem trzy segmenty, które mogą zmienić kolejność wstawiania (jak to miało miejsce w przykładzie). A klucze podobne do liczb całkowitych wcale nie trzymają się kolejności wstawiania.
Pytanie brzmi: dla jakich metod to zamówienie jest gwarantowane w specyfikacji ES2015?
Następujące metody gwarantują pokazaną kolejność:
Następujące metody / pętle nie gwarantują żadnego zamówienia:
Wniosek: Nawet w ES2015 nie powinieneś polegać na kolejności właściwości normalnych obiektów w JavaScript. Jest podatny na błędy. Użyj
Map
zamiast tego.źródło
W chwili pisania tego tekstu większość przeglądarek zwróciła właściwości w tej samej kolejności, w jakiej zostały wstawione, ale nie było to wyraźnie gwarantowane, więc nie można było na nim polegać.
Specyfikacja ECMAScript mawiała:
Jednak w ES2015 i późniejszych kluczach niecałkowitych zostaną zwrócone w kolejności wstawiania.
źródło
Cała odpowiedź jest w kontekście zgodności specyfikacji, a nie tego, co robi dany silnik w danym momencie lub historycznie.
Ogólnie nie
Rzeczywiste pytanie jest bardzo niejasne.
W jakim kontekście?
Odpowiedź brzmi: zależy to od wielu czynników. Ogólnie nie .
Czasem tak
Oto, gdzie możesz liczyć na kolejność kluczy właściwości dla zwykłego
Objects
:Object.getOwnPropertyNames()
,Reflect.ownKeys()
,Object.getOwnPropertySymbols(O)
We wszystkich przypadkach metody te obejmują niepoliczalne klucze właściwości i klucze zamówień określone przez
[[OwnPropertyKeys]]
(patrz poniżej). Różnią się rodzajem kluczowych wartości, które zawierają (String
i / lubSymbol
). W tym kontekścieString
obejmuje wartości całkowite.Object.getOwnPropertyNames(O)
Zwraca
O
własneString
właściwości klucza ( nazwy właściwości ).Reflect.ownKeys(O)
Zwraca
O
własne właściwościString
iSymbol
klucze.Object.getOwnPropertySymbols(O)
Zwraca
O
własneSymbol
właściwości.[[OwnPropertyKeys]]
Kolejność jest zasadniczo: podobna do liczby całkowitej
Strings
w porządku rosnącym, niecałkowitaStrings
w kolejności tworzenia, Symbole w kolejności tworzenia. W zależności od tego, która funkcja to wywołuje, niektóre z tych typów mogą nie zostać uwzględnione.W konkretnym języku klucze są zwracane w następującej kolejności:
Map
Jeśli interesują Cię uporządkowane mapy, powinieneś rozważyć użycie
Map
typu wprowadzonego w ES2015 zamiast zwykłegoObjects
.źródło
W nowoczesnych przeglądarkach możesz używać
Map
struktury danych zamiast obiektu.Deweloper mozilla> Mapa
źródło
W ES2015 tak jest, ale nie do tego, co myślisz
Kolejność kluczy w obiekcie nie była gwarantowana do ES2015. Zostało zdefiniowane w ramach implementacji.
Jednak w ES2015 był określona. Podobnie jak wiele rzeczy w JavaScript, zostało to zrobione dla celów kompatybilności i ogólnie odzwierciedlało istniejący nieoficjalny standard wśród większości silników JS (z wyjątkiem Ciebie).
Kolejność jest zdefiniowana w specyfikacji w ramach abstrakcyjnej operacji OrdinaryOwnPropertyKeys , która stanowi podstawę wszystkich metod iteracji po własnych kluczach obiektu. Parafrazując, kolejność jest następująca:
Wszystkie indeksy całkowitą klucze (rzeczy jak
"1123"
,"55"
itp) w rosnącej kolejności numerycznej.Wszystkie klucze łańcuchowe, które nie są indeksami liczb całkowitych, w kolejności tworzenia (najstarsze-pierwsze).
Wszystkie klucze symboli, w kolejności tworzenia (od najstarszej do pierwszej).
Głupio jest powiedzieć, że zamówienie jest niewiarygodne - jest niezawodne, po prostu prawdopodobnie nie jest to, czego chcesz, a nowoczesne przeglądarki poprawnie realizują to zamówienie.
Niektóre wyjątki obejmują metody wyliczania odziedziczonych kluczy, takie jak
for .. in
pętla.for .. in
Pętli nie gwarantuje zlecenie według specyfikacji.źródło
Począwszy od ES2015, porządek właściwości jest gwarantowany dla niektórych metod, które iterują właściwości. ale nie inni . Niestety najczęściej stosowane są metody, które nie mają gwarancji zamówienia:
Object.keys
,Object.values
,Object.entries
for..in
pętleJSON.stringify
Jednak od ES2020 porządek właściwości dla tych wcześniej niewiarygodnych metod będzie gwarantowany przez iterację specyfikacji w taki sam deterministyczny sposób jak inne, ze względu na gotową propozycję: mechanika in-in .
Podobnie jak w przypadku metod, które mają gwarantowaną kolejność iteracji (jak
Reflect.ownKeys
iObject.getOwnPropertyNames
), nieokreślone wcześniej metody będą również iterować w następującej kolejności:To właśnie robi prawie każde wdrożenie (i robiło to przez wiele lat), ale nowa propozycja uczyniła to oficjalnym.
Chociaż obecna specyfikacja pozostawia… w kolejności iteracji „ prawie zupełnie nieokreślone , prawdziwe silniki są bardziej spójne:”
Ponieważ każda implementacja już iteracyjnie iteruje właściwości, można ją wprowadzić do specyfikacji bez naruszania kompatybilności wstecznej.
Istnieje kilka dziwnych przypadków, na które obecnie nie zgadzają się wdrożenia , i w takich przypadkach wynikowe zamówienie będzie nadal nieokreślone. Aby zagwarantować porządek nieruchomości :
źródło
Jak powiedzieli inni, nie masz żadnej gwarancji co do kolejności, gdy iterujesz właściwości obiektu. Jeśli potrzebujesz uporządkowanej listy wielu pól, zasugerowałem utworzenie tablicy obiektów.
W ten sposób możesz użyć zwykłej pętli for i mieć kolejność wstawiania. W razie potrzeby można użyć metody sortowania Array, aby posortować ją do nowej tablicy.
źródło
Właśnie to odkryłem na własnej skórze.
Używając React with Redux, którego kontener stanu, który chcę przechodzić w celu wygenerowania potomków, jest odświeżany przy każdej zmianie sklepu (zgodnie z koncepcjami niezmienności Redux).
Tak więc, aby wziąć
Object.keys(valueFromStore)
, użyłemObject.keys(valueFromStore).sort()
, że przynajmniej teraz mam alfabetyczną kolejność klawiszy.źródło
Ze standardu JSON :
(moje podkreślenie).
Więc nie, nie możesz zagwarantować zamówienia.
źródło