6

Given an object definition:

var o = {x :1, y:2, z: 3, b: 4, a: 5, m: 6, X: 7};

At enumeration time, Chrome appears to respect the order in which the attributes are defined:

for (var i in o) { console.log(i, o[i]); }

Yields:

x 1
y 2
z 3
b 4
a 5
m 6
X 7

Does JavaScript and/or the JSON specify this level of order-preservation?

In either case, is it reliable?

svidgen
  • 13,099
  • 4
  • 31
  • 51
  • 1
    possible duplicate of [Elements order in a "for (… in …)" loop](http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop) – cHao Jun 06 '13 at 21:11
  • JSON does not impose any requirements on languages AFAIK. It only defines the data format. – Felix Kling Jun 07 '13 at 08:46

2 Answers2

9

No, Javascript specs explicitly do not require any particular enumeration order, they are by definition unordered.

See section 12.6.4 of the ECMAScript specification:

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

svidgen
  • 13,099
  • 4
  • 31
  • 51
Alnitak
  • 313,276
  • 69
  • 379
  • 466
  • 1
    Browsers *might* keep them ordered, but they may not. The behavior is undefined. – Rocket Hazmat Jun 06 '13 at 20:11
  • 3
    The behavior is *defined*; it's just not specified in that one regard. ECMA-262 guarantees that iteration will hit every enumerable property exactly once, and says that `Object.keys` must produce keys in the same order as the values would appear in a for...in, particularly if it makes any stronger guarantees about order. It just doesn't require a particular order. – cHao Jun 06 '13 at 20:14
  • key order does seems to work consistently in my experience. Only early chrome versions re-ordered keys AFAIK. Every mainstream browser out there i've used and tested preserves key order, even if NOT REQUIRED to do so by the spec. In short, preserving key order is a de-facto standard among major implementations. How confident that makes you is subjective, and it COULD break at any moment. – dandavis Jun 06 '13 at 20:21
  • @dandavis Given the explicit lack of an ordering requirement and _any_ version(s) of a major browser choosing not to preserve order is enough justification not to rely on it. – svidgen Jun 06 '13 at 20:24
  • @dandavis: The reason Chrome changed is that too many people made broken assumptions about the orderedness of an explicitly unordered collection. It's not Chrome that was broken, though -- it's the code that did that. An observation is not enough to justify relying on a particular order. Do *any* of the browsers actually officially specify the order they iterate in? – cHao Jun 06 '13 at 20:24
  • @chao: that seems to indicate to me that efforts ARE being made by implementators to honor the defacto standard of preserving them in def order. innerHTML worked for a long time before it was an official "standard"... I'm just telling ya'll what i've observed, nothing more. – dandavis Jun 06 '13 at 20:28
  • @dandavis Yes but innerHTML was a feature that made sense to have, guaranteeing the order that the JSON is parsed makes no sense, because the JSON is by definition unordered. – Paul Jun 06 '13 at 20:31
  • In my opinion it would be nice if at least one major browser would do it in a different order, so that incorrect scripts would break. Browser's shouldn't be consistent in ordering something that is by definition unordered, because it encourages bad programming. – Paul Jun 06 '13 at 20:33
  • @dandavis: I distinctly remember `innerHTML` not existing on a number of browsers for the longest time. But back to the point. Unless we're gonna tell ECMA to either specify the order or go screw itself, the order is explicitly unspecified -- and you're writing broken code if you rely on a particular order, regardless of how many browsers you've seen it not fail on. – cHao Jun 06 '13 at 20:35
  • @dandavis `for (feature in features) { if (feature.isDetectable) { feature.useFeatureDetection() } else { feature.avoidLikeThePlague() } }` – svidgen Jun 06 '13 at 20:38
  • 2
    @Paulpro: I wish Google had stuck to their guns and not changed Chrome. But the problem is, when bad code that works elsewhere breaks in your browser, people don't say "this site's JS sucks"...they say "this *browser* sucks". – cHao Jun 06 '13 at 20:38
  • @cHao Yeah I know, it's just frustrating. That's where a lot of the inconsistencies with how major browsers interpret HTML came from in the first place too. – Paul Jun 06 '13 at 20:49
  • @dandavis: By the way: IE9 and Chrome have a different iteration order than FF does when the keys include numeric strings. (They put the numberish keys first and in numeric order, apparently.) Just a heads up that your "defacto standard" doesn't appear all that standard.. – cHao Jun 06 '13 at 21:00
  • Apparently Google *did* stick to their guns. :) See http://stackoverflow.com/questions/280713/elements-order-in-a-for-in-loop and https://code.google.com/p/v8/issues/detail?id=164 – cHao Jun 06 '13 at 21:10
  • @chao: i never said is was the same between browsers, only that it was consistent in any browsers i've tried except early chrome. that so many good people here seem to confirm this phenomenon makes it safe in my eyes. – dandavis Jun 07 '13 at 15:12
  • 1
    @dan: It is not safe, regardless of what you have seen. Regardless of what *anyone* has seen. De facto standards mean nothing when even *the people allegedly setting the de facto standards* don't specify them. (See MDN docs on `for...in`.) Until the order is explicitly specified, you are writing inherently broken code (that just *happens* to work for now) if you rely on it. And when your code breaks, you're going to go crying about browser bugs, and we're going to have to have this conversation again, and i'll have to say "i told you so", and you'll have to go change a bunch of code anyway. – cHao Jun 07 '13 at 15:28
  • Function.toString() is not fully spec'd but a lot of scripts rely upon it. If any change happens, i would expect ECMA to spec the key order, keeping backwards compat with about everything ever written. If chrome couldn't get away with it, how would ECMA? – dandavis Jun 07 '13 at 15:31
  • @dandavis: Relying on the specifics of something that is not specified, is broken. And relying on the specifics of *deliberately and explicitly* unspecified stuff, and advocating that others do the same, should be cause to suspend one's programmer's license. :P As for your expectation about what ECMA will do: probably not gonna happen. They already *tried and failed* to come to some agreement on iteration order. – cHao Jun 07 '13 at 15:40
  • @chao: i see your point, but i never advocated for it's use. It's not a black or white issue to me. Code SHOULD be resilient enough to function without such luckiness. Last time i used this, it was to put the most common suggestions atop a datalist. If those get re-arranged one day, so be it, it's not like itt'l crash. But where it does work, folks will like having that good stuff up on top. To work-around would take more effort than the simple UX enhancement was worth. If you whole app crumbles because it one day changes, i agree; you suck as a programmer. – dandavis Jun 07 '13 at 15:49
  • @dandavis Why not receive the suggestions in a structure which supports order, like an array... – Paul Jun 07 '13 at 19:51
  • @paulpro: well, it's complicated, and we're off-topic a bit. The datalist gets rebuilt every focus() from an Object.keys().map() of a different model branch. By pre-sorting the sub-branches by popularity, Object.keys cosmetically puts the most-used keys up top, and i don't need to re-sort each focus(), maintain a cache/shadow, or alter the existing model, but the UX is a little bit better for users. – dandavis Jun 07 '13 at 20:40
1

There is no guarantee that the properties will appear in the order that they are defined.

Some browsers will retain the properties in the order that they are defined, others wont.

A JSON parser that parses the JSON into something other than a Javascript object could retain the order from the source, otherwise it's not possible to guarantee it.

Guffa
  • 640,220
  • 96
  • 678
  • 956
  • It *could* retain the order that the pairs are encountered in the string, but it would be incorrect for it to guarantee that order, since the JSON spec also states that they are unordered: `An object is an unordered collection of zero or more name/value pairs`. `{"a": 1, "b": 2}` and `{"b": 2, "a": 1}` are identical as far as JSON is concerned so the parser should parse them into structures that are also identical. – Paul Jun 06 '13 at 20:28
  • So just as most browser's do retain the order any other parser could, but no JSON parser can ever guarantee an order, otherwise it is a parser for something different than JSON which happens to have the same syntax. – Paul Jun 06 '13 at 20:35
  • @Paulpro: Interresting, then the JSON parser in jQuery is not properly implemented, because it creates objects where the properies are in different order... (in browsers that retain that order, of course) – Guffa Jun 06 '13 at 20:35
  • Well that's still correct because those objects are equivalent. There is no valid way in JavaScript to distinguish one of those objects from the other if the only difference is the order the keys are stored internally. – Paul Jun 06 '13 at 20:38
  • It would be incorrect say in PHP where associative arrays still have order, for PHP to guarantee a specific order. With Javascript, however, it is impossible to guarantee the order, because the object that is created in Javascript also has no order. – Paul Jun 06 '13 at 20:45
  • @Paulpro: The objects are equivalent, but not identical. – Guffa Jun 06 '13 at 20:53
  • They are identical up to JavaScript. The way they are stored internally doesn't need to be considered because the Javascript spec itself says that the order is unsepcified – Paul Jun 06 '13 at 20:58
  • @Paulpro: You are missing the point, and it seems that you are trying to make a point of your own, but I don't see it. What are you going on about? – Guffa Jun 06 '13 at 21:34
  • I'm just saying that the last sentence in your answer is misleading, as it is also impossible to guarantee the order in a language like PHP when using decoding to an associative array, not because PHP doesn't support order in associative arrays, but because that is incorrect in terms of JSON. – Paul Jun 06 '13 at 21:42
  • @Paulpro: I can't find that the specification says that clearly. Is it talking about JSON objects or about Javascript objects? The examples are not JSON, but Javascript. – Guffa Jun 06 '13 at 21:47
  • json.org and the RFC both say that objects in JSON are unordered collections. However you may actually be correct because the RFC also states `"A JSON parser MAY accept non-JSON forms or extensions."` which means a JSON parser could be extended to define order on JSON type objects and the parser would still be correct. – Paul Jun 06 '13 at 21:54