2

I am trying to understand what's the thing with javascript Objects while using them as an associative array.

From ECMA:

4.3.3 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.

Using them in browser (chrome):

x = { 2: 'a', 3: 'b', 1: 'c' }
> Object {1: "c", 2: "a", 3: "b"}

y = { 'b': 2, 'c': 3, 'a': 1 }
> Object {b: 2, c: 3, a: 1}

While in the first example with the numbers as keys, they became ordered, in the second example with strings, they won't ( ordered = a,b,c ).

I am using these objects with string keys and I really don't want them to change order in some stage of app(if that's even possible) because it may crash the pipeline I am using.

Question is, is this approach safe and normal for every javascript machine, or should I use other method to guarantee that order won't ever change?

Thank you!

Edit: I am using this with node.js which runs on V8 (chrome engine), which 'orders non-numerical properties in insertion order'(Felix Kling). May this behaviour of V8 change?

petomalina
  • 1,820
  • 2
  • 15
  • 23
  • 7
    Ordering of properties is undefined. That means that a JavaScript runtime is free to return the properties in any order it wants, and it doesn't even have to be the same order if you ask twice. You simply cannot rely on the ordering. If you need some fixed ordering put the property names in an array. – Pointy Jan 12 '15 at 16:50
  • 2
    _"should I use other method to guarantee that order won't ever change?"_ Yes. – j08691 Jan 12 '15 at 16:50
  • "It is an unordered collection" You can't rely on any order of object properties, the order can be whatever JS happens to give you. – Teemu Jan 12 '15 at 16:50
  • `It is an unordered collection` - This statement doesn't mean that the Javascript run-time is required preserve the order in which the properties were defined. It just means that you cannot rely on the ordering of properties to frame your logic! – jjk_charles Jan 12 '15 at 16:53
  • Well, I thought, that when you push things into ordered list, they will order, when you do it with unordered list, they will just push into the end. But thank you guys. – petomalina Jan 12 '15 at 16:53
  • 1
    Here is how Chrome is currently ordering the properties: Numerical properties come first in ascending order, then non-numerical properties in insertion order. This can change any time. – Felix Kling Jan 12 '15 at 16:54
  • If it says it's unordered, assume it's unordered. Even if a particular browser with a particular object returns the keys ordered you *cannot* assume this applies to other browser / OS combinations or will always be the case. – Matt Burland Jan 12 '15 at 16:56

4 Answers4

5

Although Chrome may guarantee property order when using numbers as indexes in objects, the ECMA specification does not say it should do that, so by guarantee I'd not rely on this behavior. I suggest you to restructure your data to use arrays when you want to keep data order.

Guilherme Sehn
  • 6,178
  • 15
  • 35
1

At the end of the day, it's because V8 uses if/else everywhere in the code to determine if it's an array index or an object property and not two separate classes to handle Array and Object separately like other JS engines:

https://lastzero.net/2009/09/object-property-ordering-in-google-chrome/

Yes, Google sticks to the specs, but it also makes it difficult to pass existing data structures from other programming languages to JS, because the ordering changes unexpectedly (even John Resig was surprised!). So you have to use different (possibly slower) data structures or use a converter, which makes code more complex.

lastzero
  • 121
  • 1
  • 9
1

It depends on the environment the code is running in, and the methods being used to iterate over the keys.

In ES5 and earlier, there is no defined order, regardless of the method used.

In ES6+, some methods which iterate over keys (but not all) are guaranteed to iterate in order over:

(1) increasing numeric keys (eg, 0, 1, 2), followed by

(2) non-numeric keys in insertion order, followed by

(3) symbols in insertion order.

The methods which are guaranteed to behave this way are, among others:

These all invoke the internal method [[OwnPropertyKeys]], which guarantees the order.

Methods which are not guaranteed to iterate in any order, even in ES6+ environments, include:

  • for..in
  • Object.keys, Object.values, Object.entries
  • JSON.stringify

These methods all call EnumerateObjectProperties, which explicitly states:

The mechanics and order of enumerating the properties is not specified

All that said, even though order isn't guaranteed, in newer environments, the above methods will almost always iterate in the same deterministic order as Reflect.ownKeys anyway. Maybe you shouldn't depend on it, but it'll probably work, at least for now.

If you want a

method to guarantee that order won't ever change?

then to dependably iterate over an object, you should iterate using Reflect.ownKeys or Object.getOwnPropertyNames.

May this behaviour of V8 change?

If you use one of the methods guaranteed to iterate in a particular order, the behavior will not change, because Javascript pretty much always retains backwards compatibility, and now that an required order has been described in the specification, no future changes will change that order.

CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
0

I read from the spec.: Arrays are ordered, Objects not. Chrome seems to make no difference between number and string of numbers. (for performance reason?) I sometimes sidestep to an additional array of keys where needed.

B.F.
  • 445
  • 6
  • 8