Muszę przejść przez obiekt JavaScript traktując go jako tablicę z niestandardowymi kluczami. Wiem, że nie jest to w pełni obsługiwane, ponieważ właściwości nie mają kolejności instruktażowej, ale ponieważ zawsze zmieniam właściwości, uważam to podejście za proste i niezawodne ... aż do teraz.
Problem występuje, gdy klucze są cyframi lub ciągami, które można rzutować jako liczby.
Kiedy uruchamiam ten kod:
var test1 = {4294966222:"A",4294966333:"A",4294966111:"A"};
var test2 = {4294968222:"A",4294968333:"A",4294968111:"A"};
for (var k in test1) {console.log(k);}
console.log("---");
for (var k in test2) {console.log(k);}
dane wyjściowe to:
4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111
Co znaczy:
- (test1) jeśli klucze są mniejsze niż 2 ^ 32 (4 294 967 296), są one automatycznie porządkowane, najpierw najmniejsze
- (test2) jeśli klucze są powyżej 2 ^ 32, NIE zostaną ponownie uporządkowane.
Pytanie brzmi: dlaczego tak się dzieje?
Ponieważ wszystkie przeglądarki, które testowałem (Google Chrome 79.0, Mozilla Firefox 71.0, Microsoft Edge 44.18362, Internet Explorer 11.535) są zgodne co do tego wyniku, musi istnieć jakaś oficjalna specyfikacja.
Aktualizacja
Przetestowałem wiele liczb, zanim odkryłem, że to kwestia progowa. Stwierdziłem dziwne, że sekwencja 2,3,1 zachowuje się inaczej niż trzy znaczniki czasu uporządkowane w ten sam sposób.
źródło
test1
itest2
. Myślę, że „problem” pochodzi z kluczowego buforowania w implementacji specyfikacji V8.4294968333
i4294968111
są większe niż2 ** 32
(co jest4294967296
). Nie są to więc tablice, więc są iterowane w kolejności tworzenia właściwości, a nie w kolejności rosnącej - to dokładnie to, co robią w skrzypcach, zgodnie z oczekiwaniami. (patrz moja odpowiedź)Odpowiedzi:
Jest to oczekiwane. Zgodnie ze specyfikacją , metoda iterująca po właściwościach
OrdinaryOwnPropertyKeys
:Rosnąca kolejność numeryczna dotyczy tylko właściwości, które są znakami tablicowymi.
Czym jest „indeks tablicy”? Sprawdź to :
Tak więc właściwości liczbowe, które są większe niż 2 ^ 32, nie są wskaźnikami tablicowymi i dlatego są iterowane w kolejności tworzenia właściwości. Jednak właściwości liczbowe, które są mniejsze niż
2^32
są wskaźnikami tablicowymi, są iterowane w porządku rosnącym numerycznie.Na przykład:
1
: Indeks tablicy, będzie iterowany ponad numerycznie10
: Indeks tablicy, będzie iterowany ponad numerycznie4294968111
: Większa niż2 ** 32
, będzie iterowana po zakończeniu wskazań tablicy, w kolejności tworzenia właściwości9999999999999
: Większa niż2 ** 32
, będzie iterowana po zakończeniu wskazań tablicy, w kolejności tworzenia właściwościNależy również pamiętać, że w przeciwieństwie do powszechnego przekonania, kolejność iteracji nieruchomości jest gwarantowana również przez specyfikację, dzięki propozycji iteracji for-in, która jest etapem 4.
źródło
Ma to związek ze sposobem, w jaki klucze obiektu przechodzą.
Zgodnie ze specyfikacjami ES6 powinno to być:
http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
Oznacza to, że jeśli wartość klucza pozostanie taka sama, jeśli zostanie przekonwertowana na 53-bitową liczbę bez znaku, a następnie traktowana jest jak indeks liczb całkowitych, który jest sortowany w porządku rosnącym numerycznie.
Jeśli to się nie powiedzie, jest traktowane jak klucz łańcuchowy, które są uporządkowane w sposób, w jaki zostały dodane do obiektu.
Problem polega na tym, że wszystkie główne przeglądarki nie stosują się jeszcze do tej specyfikacji i zamiast tego używają indeksu tablicowego, który jest ograniczony do liczby dodatniej do . Więc wszystko powyżej tego limitu jest tak naprawdę kluczem łańcuchowym.
źródło