Does JavaScript Guarantee Object Property Order?

2018-12-30 22:02发布

If I create an object like this:

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

Will the resulting object always look like this?

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

That is, will the properties be in the same order that I added them?

标签: javascript
8条回答
低头抚发
2楼-- · 2018-12-30 22:26

Current Language Spec: technically, order is unspecified.

Current Browsers: order is preserved with the major exception of keys like "7" that parse as integers and are handled differently by Chrome/V8.

Future Language Spec (>ES2015): Generally, you can expect that things ordered today will not become unordered. New APIs will guarantee order; existing APIs are difficult to change. See JMM's answer for more details.

The best link below is in Tim Down's comment:

http://code.google.com/p/v8/issues/detail?id=164

That bug covers in detail the design decisions involved for Chrome's implementation of key ordering. One take-away is that for string keys that don't parse to an integer (ie "a" or "b", but NOT "3"), keys are printed in insertion order on all major browsers and while this behavior is not "standardized", it IS considered a significant backwards-compatibility issue by browser vendors. Use at your own risk.

Per one of the (rather opinionated) comments:

Standards always follow implementations, that's where XHR came from, and Google does the same thing by implementing Gears and then embracing equivalent HTML5 functionality. The right fix is to have ECMA formally incorporate the de-facto standard behavior into the next rev of the spec.

If you rely on insertion order, you are outside the ECMAScript spec, but within the de-facto standard of common browser behavior as long as your keys don't parse as integers.

查看更多
低头抚发
3楼-- · 2018-12-30 22:26

At the time of writing, most browsers did return properties in the same order as they were inserted, but it was explicitly not guaranteed behaviour so shouldn't have been relied upon.

The ECMAScript specification used to say:

The mechanics and order of enumerating the properties ... is not specified.

However in ES2015 and later non-integer keys will be returned in insertion order.

查看更多
忆尘夕之涩
4楼-- · 2018-12-30 22:33

No, properties order in objects is not guaranteed in JavaScript; you need to use an Array.

Definition of an Object from ECMAScript Third Edition (pdf):

4.3.3 Object

An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.

Since ECMAScript 2015, using the Map object could be an alternative. A Map shares some similarities with an Object and guarantees the keys order:

A Map iterates its elements in insertion order, whereas iteration order is not specified for Objects.

查看更多
临风纵饮
5楼-- · 2018-12-30 22:33

As others have stated, you have no guarantee as to the order when you iterate over the properties of an object. If you need an ordered list of multiple fields I suggested creating an array of objects.

var myarr = [{somfield1: 'x', somefield2: 'y'},
{somfield1: 'a', somefield2: 'b'},
{somfield1: 'i', somefield2: 'j'}];

This way you can use a regular for loop and have the insert order. You could then use the Array sort method to sort this into a new array if needed.

查看更多
爱死公子算了
6楼-- · 2018-12-30 22:35

This whole answer is in the context of spec compliance, not what any engine does at a particular moment or historically.

Generally, no

The actual question is very vague.

will the properties be in the same order that I added them

In what context?

The answer is: it depends on a number of factors. In general, no.

Sometimes, yes

Here is where you can count on property key order for plain Objects:

  • ES2015 compliant engine
  • Own properties
  • Object.getOwnPropertyNames(), Reflect.ownKeys(), Object.getOwnPropertySymbols(O)

In all cases these methods include non-enumerable property keys and order keys as specified by [[OwnPropertyKeys]] (see below). They differ in the type of key values they include (String and / or Symbol). In this context String includes integer values.

Object.getOwnPropertyNames(O)

Returns O's own String-keyed properties (property names).

Reflect.ownKeys(O)

Returns O's own String- and Symbol-keyed properties.

Object.getOwnPropertySymbols(O)

Returns O's own Symbol-keyed properties.

[[OwnPropertyKeys]]

The order is essentially: integer-like Strings in ascending order, non-integer-like Strings in creation order, Symbols in creation order. Depending which function invokes this, some of these types may not be included.

The specific language is that keys are returned in the following order:

  1. ... each own property key P of O [the object being iterated] that is an integer index, in ascending numeric index order

  2. ... each own property key P of O that is a String but is not an integer index, in property creation order

  3. ... each own property key P of O that is a Symbol, in property creation order

Map

If you're interested in ordered maps you should consider using the Map type introduced in ES2015 instead of plain Objects.

查看更多
像晚风撩人
7楼-- · 2018-12-30 22:43

Property order in normal Objects is a complex subject in Javascript.

While in ES5 explicitly no order has been specified, ES2015 has an order in certain cases. Given is the following object:

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},
});

This results in the following order (in certain cases):

Object {
  0: 0,
  1: "1",
  2: "2",
  b: "b",
  a: "a",
  m: function() {},
  Symbol(): "sym"
}
  1. integer-like keys in ascending order
  2. normal keys in insertion order
  3. Symbols in insertion order

Thus, there are three segments, which may alter the insertion order (as happened in the example). And integer-like keys don't stick to the insertion order at all.

The question is, for what methods this order is guaranteed in the ES2015 spec?

The following methods guarantee the order shown:

  • Object.assign
  • Object.defineProperties
  • Object.getOwnPropertyNames
  • Object.getOwnPropertySymbols
  • Reflect.ownKeys

The following methods/loops guarantee no order at all:

  • Object.keys
  • for..in
  • JSON.parse
  • JSON.stringify

Conclusion: Even in ES2015 you shouldn't rely on the property order of normal objects in Javascript. It is prone to errors. Use Map instead.

查看更多
登录 后发表回答