Elements order in a "for (… in …)" loop

JavascriptFor Loop

Javascript Problem Overview


Does the "for…in" loop in Javascript loop through the hashtables/elements in the order they are declared? Is there a browser which doesn't do it in order?
The object I wish to use will be declared once and will never be modified.

Suppose I have:

var myObject = { A: "Hello", B: "World" };

And I further use them in:

for (var item in myObject) alert(item + " : " + myObject[item]);

Can I expect 'A : "Hello"' to always come before 'B : "World"' in most decent browsers?

Javascript Solutions


Solution 1 - Javascript

Quoting John Resig:

> Currently all major browsers loop over the properties of an object in the order in > which they were defined. Chrome does this as well, except for a couple cases. [...] > This behavior is explicitly left undefined by the ECMAScript specification. > In ECMA-262, section 12.6.4: > > > The mechanics of enumerating the properties ... is implementation dependent. > > However, specification is quite different from implementation. All modern implementations > of ECMAScript iterate through object properties in the order in which they were defined. > Because of this the Chrome team has deemed this to be a bug and will be fixing it.

All browsers respect definition order with the exception of Chrome and Opera which do for every non-numerical property name. In these two browsers the properties are pulled in-order ahead of the first non-numerical property (this is has to do with how they implement arrays). The order is the same for Object.keys as well.

This example should make it clear what happens:

var obj = {
  "first":"first",
  "2":"2",
  "34":"34",
  "1":"1",
  "second":"second"
};
for (var i in obj) { console.log(i); };
// Order listed:
// "1"
// "2"
// "34"
// "first"
// "second"

The technicalities of this are less important than the fact that this may change at any time. Do not rely on things staying this way.

In short: Use an array if order is important to you.

Solution 2 - Javascript

Bumping this a year later...

It is 2012 and the major browsers still differ:

function lineate(obj){
    var arr = [], i;
    for (i in obj) arr.push([i,obj[i]].join(':'));
    console.log(arr);
}
var obj = { a:1, b:2, c:3, "123":'xyz' };
/* log1 */  lineate(obj);
obj.a = 4;
/* log2 */  lineate(obj);
delete obj.a;
obj.a = 4;
/* log3 */  lineate(obj);

gist or test in current browser

Safari 5, Firefox 14

["a:1", "b:2", "c:3", "123:xyz"]
["a:4", "b:2", "c:3", "123:xyz"]
["b:2", "c:3", "123:xyz", "a:4"]

Chrome 21, Opera 12, Node 0.6, Firefox 27

["123:xyz", "a:1", "b:2", "c:3"]
["123:xyz", "a:4", "b:2", "c:3"]
["123:xyz", "b:2", "c:3", "a:4"]

IE9

[123:xyz,a:1,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 
[123:xyz,a:4,b:2,c:3] 

Solution 3 - Javascript

From the ECMAScript Language Specification, section 12.6.4 (on the for .. in loop):

>The mechanics of enumerating the properties is implementation dependent. The order of enumeration is defined by the object.

And section 4.3.3 (definition of "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.

I guess that means you cant rely on the properties being enumerated in a consistent order across JavaScript implementations. (It would be bad style anyway to rely on implementation-specific details of a language.)

If you want your order defined, you will need to implement something that defines it, like an array of keys that you sort before accessing the object with it.

Solution 4 - Javascript

The elements of an object that for/in enumerates are the properties that don't have the DontEnum flag set. The ECMAScript, aka Javascript, standard explicitly says that "An Object is an unordered collection of properties" (see http://www.mozilla.org/js/language/E262-3.pdf section 8.6).

It's not going to be standards conformant (i.e. safe) to assume all Javascript implementations will enumerate in declaration order.

Solution 5 - Javascript

Iteration order is also confused with respect to deleting of properties, but in this case with IE only.

var obj = {};
obj.a = 'a';
obj.b = 'b';
obj.c = 'c';

// IE allows the value to be deleted...
delete obj.b;

// ...but remembers the old position if it is added back later
obj.b = 'bb';
for (var p in obj) {
    alert(obj[p]); // in IE, will be a, bb, then c;
                   // not a, c, then bb as for FF/Chrome/Opera/Safari
}

The desire for changing the spec to fix the iteration order seems to be quite a popular desire among developers if the discussion at http://code.google.com/p/v8/issues/detail?id=164 is any indication.

Solution 6 - Javascript

in IE6, the order is not guaranteed.

Solution 7 - Javascript

The order cannot be trusted. Both Opera and Chrome return the list of properties unordered.

<script type="text/javascript">
var username = {"14719":"A","648":"B","15185":"C"};

for (var i in username) {
  window.alert(i + ' => ' + username[i]);
}
</script>

The code above shows B, A, C in Opera and C, A, B in Chrome.

Solution 8 - Javascript

This does not answer the question per se, but offers a solution to the basic problem.

Assuming that you cannot rely on order to preserved, why not use an array of objects with key and value as properties?

var myArray = [
    {
        'key'   : 'key1'
        'value' : 0
    },
    {
        'key'   : 'key2',
        'value' : 1
    } // ...
];

Now, it is up to you to ensure that the keys are unique (assuming that this is also important to you). As well, direct addressing changes, and for (...in...) now returns indices as 'keys'.

> console.log(myArray[0].key);
key1

> for (let index in myArray) {console.log(myArray[index].value);}
0
1

See the Pen https://codepen.io/JDQ/pen/deNqKZ/">for (...in...) addressing in order by JDQ (https://codepen.io/JDQ">@JDQ</a>;) on https://codepen.io">CodePen</a>.</p>

Solution 9 - Javascript

As stated by other answers, no, the order is not guaranteed.

If you want to iterate in order, you can do something like:

let keys = Object.keys(myObject);
for (let key of keys.sort()) {
  let value = myObject[key];
  
  // Do what you want with key and value 
}

Note that performance-wise, this is not optimal, but that's the price when you want a nice alphabetical display.

Solution 10 - Javascript

As of 2022,

I have just found out (to my surprise), that Chrome does not respect the definition order. It rather sorts it alphabetically but not naturally. For example key "a12" comes BEFORE "a3". So be careful.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionchakritView Question on Stackoverflow
Solution 1 - JavascriptBorgarView Answer on Stackoverflow
Solution 2 - JavascriptdvdrtrgnView Answer on Stackoverflow
Solution 3 - JavascriptTomalakView Answer on Stackoverflow
Solution 4 - JavascriptAdam WrightView Answer on Stackoverflow
Solution 5 - JavascriptBrett ZamirView Answer on Stackoverflow
Solution 6 - JavascriptAriView Answer on Stackoverflow
Solution 7 - JavascriptKouber SaparevView Answer on Stackoverflow
Solution 8 - JavascriptJDQView Answer on Stackoverflow
Solution 9 - JavascriptThierry J.View Answer on Stackoverflow
Solution 10 - JavascriptLukáš ŘádekView Answer on Stackoverflow