211

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?

kiamlaluno
  • 24,790
  • 16
  • 70
  • 85
chakrit
  • 57,172
  • 24
  • 125
  • 160
  • 61
    Becasue they would only be testing a subset of potential browsers and variants. Not to mention any future browsers. It is plain wrong to assume a non-failing test provides any sort of concrete proof. – James Hughes Nov 11 '08 at 12:23
  • 6
    I doubt my own limited javascript ability will be better than the SO crowd. Besides who knows what strange browser lurks out there? And you can see in the answer that GChrome does have a bug which will not be apparent in my simple example case. – chakrit Nov 11 '08 at 13:31
  • possible duplicate of [Does JavaScript Guarantee Object Property Order?](http://stackoverflow.com/q/5525795/1048572) – Bergi Jun 25 '15 at 14:52
  • 2
    also relevant: [Does ES6 introduce a well-defined order of enumeration for object properties?](http://stackoverflow.com/q/30076219/1048572) – Bergi Dec 11 '15 at 10:10
  • Does this answer your question? [Does ES6 introduce a well-defined order of enumeration for object properties?](https://stackoverflow.com/questions/30076219/does-es6-introduce-a-well-defined-order-of-enumeration-for-object-properties) – Henke Feb 13 '21 at 09:42

9 Answers9

220

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.

Community
  • 1
  • 1
Borgar
  • 34,011
  • 5
  • 36
  • 41
  • 4
    Not really. Chrome doesn't implement the same order as other browsers: http://code.google.com/p/v8/issues/detail?id=164 – Tim Down Nov 30 '10 at 23:13
  • @Tim, Thanks for the nudge. I've updated the answer to reflect the current state of reality. – Borgar Dec 03 '10 at 00:02
  • 22
    "Use an array if order is important to you": What about when you're using JSON? – HM2K Feb 10 '11 at 23:40
  • 11
    @HM2K, Same thing, spec says "An object is an unordered collection of zero or more name/value pairs." JSON isn't JavaScript: A server doesn't need to (and probably won't) respect the order you hand it. – Borgar Feb 12 '11 at 01:40
  • 7
    Firefox since its 21 version doesn't seem to respect the insertion order anymore. – Doc Davluz Jun 14 '13 at 07:26
  • 1
    Respecting insertion order for array indices would either mean that arrays (or the particular array being tested) is not backed by a real array or it is backed by a real array and for some reason the insertion order is stored separately. So it is good that is not happening. It is no surprise IE10, Chrome and Firefox all log `true` [here](http://jsfiddle.net/ARzUh/2/). Properties should be in insertion order because of the usage of shapes/hidden classes. – Esailija Jul 30 '13 at 01:33
  • 3
    This answer is false in ES2015. – Benjamin Gruenbaum Sep 30 '15 at 18:54
  • @Borgar Is there any news about this matter in 2019 ? – Orelsanpls Jul 10 '19 at 09:18
  • @BenjaminGruenbaum Is there any news about this matter in 2019 ? – Orelsanpls Jul 10 '19 at 09:18
  • 1
    @GrégoryNEUT yes but only for some methods, `EnumerateObjectProperties` and `EnumerableOwnPropertyNames` order is implementation dependent. Maps iterate with insertion order for example. Object.keys order is still implementation dependent apparently. – Benjamin Gruenbaum Jul 10 '19 at 10:47
54

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] 
dvdrtrgn
  • 1,110
  • 11
  • 19
  • 16
    what's the problem here? Exactly as the specification says, it's an unordered list of key/val pairs. – nickf Feb 12 '13 at 09:28
  • no one said the spec was "wrong"... There exists an annoyingly inconsistant treatment in browser handling programmatic order of access to these "unordered" props – dvdrtrgn Feb 22 '13 at 00:11
  • 7
    nickf: the implementations are right in that they do what the spec says. I think everyone agrees that the javascript spec is.. well, I don't want to use the word "wrong", how about "extremely stupid and annoying"? :P – boxed Feb 25 '13 at 02:05
  • 10
    @boxed: Think about objects as a hash map (table/whatever). In most languages (Java, Python, etc) these kinds of data structures are not sorted. So it is not surprising that this is the same case in JavaScript as well and it certainly does not make the specification wrong or stupid. – Felix Kling Apr 12 '13 at 09:53
  • 9
    I honestly don't see the point of this answer (sorry). The order in which properties are iterated over is an implementation detail, and browsers use different JavaScript engines, so it is expected that the order differs. This won't change. – Felix Kling Apr 12 '13 at 09:59
  • 1
    I know how it works and I know it won't change in any reasonable time. That doesn't change the fact that it sucks :P – boxed Apr 13 '13 at 13:48
  • 2
    In a state of art implementation you will receive integer properties in numerical value order due to being backed by a real array, and named properties will be received in insertion order due to hidden classes/shapes formulation. What can vary is whether they list the integer properties first or named properties first. The addition of `delete` is interesting because at least in V8, it instantly causes the object to be backed up by a hash table. However, the hash table in V8 stores in insertion order. Most interesting result here is IE, I wonder what kind of ugliness they do to pull that off... – Esailija Jul 30 '13 at 01:49
28

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.

Tomalak
  • 306,836
  • 62
  • 485
  • 598
10

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.

Adam Wright
  • 47,483
  • 11
  • 126
  • 149
5

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.

Brett Zamir
  • 12,481
  • 5
  • 45
  • 68
3

in IE6, the order is not guaranteed.

2

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.

Kouber Saparev
  • 6,277
  • 2
  • 23
  • 23
1

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 indexes as 'keys'.

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

> for (let index in myArray) {console.log(myArray[index].value);}
0
1
See the Pen for (...in...) addressing in order by JDQ (@JDQ) on CodePen.
JDQ
  • 268
  • 3
  • 10
0

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.

Thierry J.
  • 1,967
  • 13
  • 22