Ich muss ein JavaScript-Objekt durchlaufen, das es als Array mit benutzerdefinierten Schlüsseln behandelt. Ich weiß, dass dies nicht vollständig unterstützt wird, da Eigenschaften keine instrumentelle Reihenfolge haben, aber da ich die Eigenschaften immer neu ordne, fand ich diesen Ansatz einfach und zuverlässig ... bis jetzt.
Das Problem tritt auf, wenn die Schlüssel Zahlen oder Zeichenfolgen sind, die als Zahlen umgewandelt werden können.
Wenn ich diesen Code ausführe:
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);}
Die Ausgabe ist:
4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111
Was bedeutet:
- (test1) Wenn die Tasten unter 2 ^ 32 (4,294,967,296) liegen, werden sie automatisch neu angeordnet, die kleinste zuerst
- (test2) Wenn die Tasten über 2 ^ 32 liegen, werden sie NICHT neu angeordnet.
Die Frage ist: Warum passiert das?
Da alle von mir getesteten Browser (Google Chrome 79.0, Mozilla Firefox 71.0, Microsoft Edge 44.18362, Internet Explorer 11.535) dieser Ausgabe zustimmen, muss es einige offizielle Spezifikationen geben.
Aktualisieren
Ich habe viele Zahlen getestet, bevor ich herausgefunden habe, dass es sich um eine Schwellenfrage handelt. Ich fand es seltsam, dass sich die Sequenz 2,3,1 anders verhält als drei Zeitstempel, die auf die gleiche Weise bestellt wurden.
quelle
test1
und sehentest2
. Ich denke, das "Problem" liegt im Schlüssel-Caching in der V8-Implementierung der Spezifikation.4294968333
und4294968111
sind größer als2 ** 32
(das ist4294967296
). Sie sind also keine Array-Angaben, daher werden sie in der Reihenfolge der Eigenschaftserstellung und nicht in aufsteigender numerischer Reihenfolge wiederholt - genau das tun sie erwartungsgemäß in der Geige. (siehe meine Antwort)Antworten:
Dies wird erwartet. Gemäß der Spezifikation führt die Methode, die über Eigenschaften iteriert, Folgendes aus
OrdinaryOwnPropertyKeys
:Die aufsteigende numerische Reihenfolge gilt nur für Eigenschaften, die Array-Anzeigen sind.
Was ist ein "Array-Index"? Schauen Sie es oben: :
Numerische Eigenschaften, die größer als 2 ^ 32 sind, sind also keine Array-Angaben und werden daher in der Reihenfolge der Eigenschaftserstellung iteriert. Allerdings numerische Eigenschaften , die weniger als
2^32
sind Array indicies und werden in aufsteigender numerischer Reihenfolge iteriert.Also zum Beispiel:
1
: Array-Index, wird numerisch durchlaufen10
: Array-Index, wird numerisch durchlaufen4294968111
: Größer als2 ** 32
, wird nach Abschluss der Array-Angaben in der Reihenfolge der Eigenschaftserstellung wiederholt9999999999999
: Größer als2 ** 32
, wird nach Abschluss der Array-Angaben in der Reihenfolge der Eigenschaftserstellung wiederholtAuch halten Sie daran , dass, entgegen der landläufigen Meinung, Eigenschaft Iterationsreihenfolge wird durch die Spezifikation und garantiert dank den for-in - Iteration Vorschlag , das ist Stufe 4.
quelle
Dies hängt damit zusammen, wie die Schlüssel eines Objekts durchlaufen werden.
Gemäß den ES6-Spezifikationen sollte es sein:
http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
Das heißt, wenn der Wert eines Schlüssels gleich bleibt, wenn er in eine vorzeichenlose 53-Bit-Zahl und zurück konvertiert wird, wird er als ganzzahliger Index behandelt, der in aufsteigender numerischer Reihenfolge sortiert wird.
Wenn dies fehlschlägt, wird es als Zeichenfolgenschlüssel behandelt, die so angeordnet sind, wie sie dem Objekt hinzugefügt wurden.
Der Haken dabei ist, dass alle gängigen Browser dieser Spezifikation noch nicht folgen und stattdessen einen Array-Index verwenden, der auf eine positive Zahl bis beschränkt ist . Alles, was über dieser Grenze liegt, ist also tatsächlich ein String-Schlüssel.
quelle