964 Stimmen

Garantiert JavaScript die Reihenfolge der Objekteigenschaften?

Wenn ich ein Objekt wie dieses erstelle:

var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";

Wird das resultierende Objekt immer so aussehen?

{ prop1 : "Foo", prop2 : "Bar" }

Das heißt, werden die Eigenschaften in der gleichen Reihenfolge angezeigt, in der ich sie hinzugefügt habe?

2 Stimmen

5 Stimmen

741voto

bpierre Punkte 9968

Die Iterationsreihenfolge für Objekte ist wie folgt eine bestimmte Anzahl von Regeln seit ES2015, aber sie folgt nicht (immer) der Einfügereihenfolge . Einfach ausgedrückt ist die Iterationsreihenfolge eine Kombination aus der Einfügereihenfolge für Zeichenkettenschlüssel und der aufsteigenden Reihenfolge für zahlenähnliche Schlüssel:

// key order: 1, foo, bar
const obj = { "foo": "foo", "1": "1", "bar": "bar" }

Mit einem Array oder einer Map Objekt kann ein besserer Weg sein, dies zu erreichen. Map weist einige Ähnlichkeiten auf mit Object y garantiert, dass die Schlüssel in der Reihenfolge der Einfügung iteriert werden , ohne Ausnahme:

Die Schlüssel in Map sind geordnet, während die zum Objekt hinzugefügten Schlüssel nicht geordnet sind. Bei der Iteration über ein Map-Objekt werden daher die Schlüssel in der Reihenfolge des Einfügens zurückgegeben. (Beachten Sie, dass in der ECMAScript 2015-Spezifikation Objekte die Erstellungsreihenfolge für String- und Symbolschlüssel beibehalten, so dass die Durchquerung eines Objekts mit nur String-Schlüsseln Schlüssel in der Reihenfolge der Einfügung ergeben würde.)

Vor ES2015 war die Reihenfolge der Eigenschaften in Objekten übrigens nicht garantiert. Definition eines Objekts aus ECMAScript Dritte Ausgabe (pdf) :

4.3.3 Objekt

Ein Objekt ist ein Mitglied der Typs Object. Es ist eine ungeordnete Sammlung von Eigenschaften von denen jede enthält einen primitiven Wert, ein Objekt oder Funktion. Eine Funktion, die in einer Eigenschaft eines Objekts gespeichert ist, wird als Methode.

7 Stimmen

Das Verhalten von Integer-Schlüsseln ist nicht in allen Browsern gleich. Bei einigen älteren Browsern werden Ganzzahlschlüssel in Einfügereihenfolge (mit den Zeichenkettenschlüsseln) und bei anderen in aufsteigender Reihenfolge durchlaufen.

6 Stimmen

@DaveDopson - Richtig - veraltete Browser folgen nicht der aktuellen Spezifikation, weil sie nicht aktualisiert werden.

1 Stimmen

Ist "Ganzzahlige Schlüssel" korrekt? Nach meinen begrenzten Tests werden nur ganzzahlige Schlüssel / nicht-negative Integer-Schlüssel in aufsteigender Reihenfolge sortiert.

324voto

Dave Dopson Punkte 39640

JA (aber nicht immer in der Reihenfolge der Einfügung).

Die meisten Browser iterieren die Objekteigenschaften als:

  1. Ganzzahlige Schlüssel in aufsteigender Reihenfolge (und Zeichenketten wie "1", die als Ints geparst werden)
  2. String-Schlüssel, in Einfügereihenfolge (ES2015 garantiert dies, und alle Browser entsprechen dem)
  3. Symbolnamen, in Einfügereihenfolge (ES2015 garantiert dies und alle Browser erfüllen diese Anforderungen)

Einige ältere Browser kombinieren die Kategorien Nr. 1 und Nr. 2, indem sie alle Schlüssel in der Einfügereihenfolge iterieren. Wenn Ihre Schlüssel als Ganzzahlen geparst werden können, ist es am besten, sich nicht auf eine bestimmte Iterationsreihenfolge zu verlassen.

Aktuelle Sprachspezifikation (seit ES2015) Die Einfügereihenfolge wird beibehalten, außer im Fall von Schlüsseln, die als Ganzzahlen geparst werden (z. B. "7" oder "99"), wo das Verhalten zwischen den Browsern variiert. Chrome/V8 zum Beispiel respektiert die Einfügereihenfolge nicht, wenn die Tasten als numerisch geparst werden.

Alte Sprachspezifikation (vor ES2015) : Die Iterationsreihenfolge war technisch undefiniert, aber alle wichtigen Browser entsprachen dem ES2015-Verhalten.

Beachten Sie, dass das Verhalten von ES2015 ein gutes Beispiel dafür ist, dass die Sprachspezifikation durch das bestehende Verhalten bestimmt wird und nicht umgekehrt. Um einen tieferen Sinn für diese Rückwärtskompatibilität zu bekommen, siehe http://code.google.com/p/v8/issues/detail?id=164 ein Chrome-Fehler, der die Design-Entscheidungen hinter dem Iterationsverhalten von Chrome im Detail beschreibt. In einem der (ziemlich eigenwilligen) Kommentare zu diesem Fehlerbericht heißt es:

Standards folgen immer auf Implementierungen, daher kommt XHR, und Google tut dasselbe, indem es Gears implementiert und dann die entsprechenden HTML5-Funktionen übernimmt. Die richtige Lösung besteht darin, dass die ECMA das De-facto-Standardverhalten in die nächste Überarbeitung der Spezifikation formell aufnimmt.

2 Stimmen

@BenjaminGruenbaum - das war genau mein Punkt. Ab 2014 hatten alle großen Anbieter eine gemeinsame Implementierung, so dass die Standards schließlich folgen werden (d. h. 2015).

5 Stimmen

Im Übrigen: Reagieren Sie createFragment API stützt sich bereits auf diese...

9 Stimmen

@BenjaminGruenbaum Ihr Kommentar ist falsch. In ES2015 ist die Reihenfolge nur für ausgewählt Methoden. Siehe Antwort von ftor unten.

158voto

Die Reihenfolge der Eigenschaften in normalen Objekten ist ein komplexes Thema in JavaScript.

Während in ES5 explizit keine Reihenfolge festgelegt wurde, definierte ES2015 eine Reihenfolge in bestimmten Fällen, und die nachfolgenden Änderungen der Spezifikation haben die Reihenfolge zunehmend definiert (ab ES2020 sogar die for-in Schleifenanordnung). Gegeben ist das folgende Objekt:

const o = Object.create(null, {
  m: {value: function() {}, enumerable: true},
  "2": {value: "2", enumerable: true},
  "b": {value: "b", enumerable: true},
  0: {value: 0, enumerable: true},
  [Symbol()]: {value: "sym", enumerable: true},
  "1": {value: "1", enumerable: true},
  "a": {value: "a", enumerable: true},
});

Daraus ergibt sich (in bestimmten Fällen) die folgende Reihenfolge:

Object {
  0: 0,
  1: "1",
  2: "2",
  b: "b",
  a: "a",
  m: function() {},
  Symbol(): "sym"
}

Die Reihenfolge für "eigene" (nicht vererbte) Eigenschaften ist:

  1. Integer-ähnliche Schlüssel in aufsteigender Reihenfolge
  2. Zeichenkettenschlüssel in Einfügereihenfolge
  3. Symbole in Einfügereihenfolge

Es gibt also drei Segmente, die die Einfügereihenfolge ändern können (wie im Beispiel geschehen). Und ganzzahlige Schlüssel halten sich überhaupt nicht an die Einfügereihenfolge.

In ES2015 folgten nur bestimmte Methoden dieser Reihenfolge:

  • Objekt.zuweisen
  • Object.defineProperties
  • Object.getOwnPropertyNames
  • Object.getOwnPropertySymbols
  • Reflect.ownKeys
  • JSON.parse
  • JSON.stringify

Ab ES2020 tun dies alle anderen (einige in den Spezifikationen zwischen ES2015 und ES2020, andere in ES2020), einschließlich:

  • Object.keys, Object.entries, Object.values, ...
  • für in

Am schwierigsten war es, die folgenden Punkte festzulegen for-in weil sie als einzige vererbte Eigenschaften enthält. Das wurde getan (in allen Fällen mit Ausnahme von Randfällen) in ES2020. Die folgende Liste aus dem verlinkten (inzwischen abgeschlossenen) Vorschlag enthält die Randfälle, in denen die Reihenfolge nicht festgelegt ist:

  • Weder das Objekt, das iteriert wird, noch irgendetwas in seiner Prototypenkette ist ein Proxy, ein typisiertes Array, ein Modul-Namespace-Objekt oder ein exotisches Host-Objekt.
  • Weder das Objekt noch irgendetwas in seiner Prototypenkette ändert seinen Prototyp während der Iteration.
  • Weder das Objekt noch irgendetwas in seiner Prototypenkette hat eine Eigenschaft, die während der Iteration gelöscht wird.
  • In der Prototypenkette des Objekts wurde während der Iteration keine Eigenschaft hinzugefügt.
  • Keine Eigenschaft des Objekts oder irgendetwas in seiner Prototypenkette ändert seine Aufzählbarkeit während der Iteration.
  • Keine nicht aufzählbare Eigenschaft überschattet eine aufzählbare.

Schlussfolgerung: Auch in ES2015 sollte man sich nicht auf die Eigenschaftsreihenfolge von normalen Objekten in JavaScript verlassen. Sie ist anfällig für Fehler. Wenn Sie geordnete benannte Paare benötigen, verwenden Sie Map die nur die Einfügereihenfolge verwendet. Wenn Sie nur die Reihenfolge benötigen, verwenden Sie ein Array oder Set (die ebenfalls eine reine Einfügereihenfolge verwendet).

80voto

Alnitak Punkte 324207

Zum Zeitpunkt der Erstellung dieses Dokuments gaben die meisten Browser die Eigenschaften in der gleichen Reihenfolge zurück, in der sie eingefügt wurden, aber dies war ausdrücklich kein garantiertes Verhalten, so dass man sich nicht darauf verlassen sollte.

El ECMAScript-Spezifikation pflegte zu sagen:

Die Mechanik und Reihenfolge der Aufzählung der Eigenschaften ... ist nicht festgelegt.

In ES2015 und später werden jedoch nicht-ganzzahlige Schlüssel in Einfügereihenfolge zurückgegeben.

17 Stimmen

Chrome implementiert eine andere Reihenfolge als andere Browser. Siehe code.google.com/p/v8/issues/detail?id=164

9 Stimmen

Opera 10.50 und höher sowie der IE9 entsprechen der Reihenfolge von Chrome. Firefox und Safari sind jetzt eine Minderheit (und beide verwenden auch unterschiedliche Reihenfolgen für Objekte/Arrays).

0 Stimmen

Vielleicht können wir die Dinge klären, indem wir auf die Fälle hinweisen, in denen der Auftrag nicht eingehalten werden würde. D.h., liege ich falsch oder gibt es nur die Möglichkeit, dass Ihre Eigenschaften numerische Zeichenfolgen sind?

48voto

JMM Punkte 24490

Diese ganze Antwort bezieht sich auf die Einhaltung der Spezifikationen und nicht darauf, was ein Motor zu einem bestimmten Zeitpunkt oder in der Vergangenheit getan hat.

In der Regel keine

Die eigentliche Frage ist sehr vage.

werden die Eigenschaften in der gleichen Reihenfolge angezeigt, in der ich sie hinzugefügt habe

In welchem Zusammenhang?

Die Antwort lautet: Das hängt von einer Reihe von Faktoren ab. Ganz allgemein, ノー .

Manchmal, ja

Hier können Sie sich auf die Bestellung von Immobilienschlüsseln für einfache Objects :

  • ES2015-konformer Motor
  • Eigene Immobilien
  • Object.getOwnPropertyNames() , Reflect.ownKeys() , Object.getOwnPropertySymbols(O)

In allen Fällen umfassen diese Methoden nicht aufzählbare Eigenschaftsschlüssel und Bestellschlüssel, wie sie in [[OwnPropertyKeys]] (siehe unten). Sie unterscheiden sich durch die Art der Schlüsselwerte, die sie enthalten ( String und / oder Symbol ). In diesem Zusammenhang String enthält ganzzahlige Werte.

Object.getOwnPropertyNames(O)

Rückgabe O eigene String -Schlüssel-Eigenschaften ( Eigenschaftsnamen ).

Reflect.ownKeys(O)

Rückgabe O eigene String - und Symbol -Schlüssel-Eigenschaften.

Object.getOwnPropertySymbols(O)

Rückgabe O eigene Symbol -Schlüssel-Eigenschaften.

[[OwnPropertyKeys]]

Die Reihenfolge ist im Wesentlichen: ganzzahlig Strings in aufsteigender Reihenfolge, nicht-ganzzahlig Strings in der Reihenfolge der Erstellung, Symbole in der Reihenfolge der Erstellung. Je nachdem, welche Funktion diese Funktion aufruft, werden einige dieser Typen möglicherweise nicht berücksichtigt.

Die spezifische Sprache sieht vor, dass die Schlüssel in der folgenden Reihenfolge zurückgegeben werden:

  1. ... jeder seinen eigenen Eigentumsschlüssel P de O [das zu iterierende Objekt], das ein ganzzahliger Index ist, in aufsteigender numerischer Indexreihenfolge

  2. ... jeder seinen eigenen Eigentumsschlüssel P de O die eine Zeichenfolge, aber kein ganzzahliger Index ist, in der Reihenfolge der Eigenschaftserstellung

  3. ... jeder seinen eigenen Eigentumsschlüssel P de O das ist ein Symbol, in der Reihenfolge der Eigenschaftserstellung

Map

Wenn Sie an geordneten Karten interessiert sind, sollten Sie die Map Typ, der in ES2015 anstelle des einfachen Objects .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X