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?
16 Answers 16
The iteration order for objects follows a certain set of rules since ES2015, but it does not (always) follow the insertion order. Simply put, the iteration order is a combination of the insertion order for strings keys, and ascending order for number-like keys:
// key order: 1, foo, bar
const obj = { "foo": "foo", "1": "1", "bar": "bar" }
Using an array or a Map
object can be a better way to achieve this. Map
shares some similarities with Object
and guarantees the keys to be iterated in order of insertion, without exception:
The keys in Map are ordered while keys added to object are not. Thus, when iterating over it, a Map object returns keys in order of insertion. (Note that in the ECMAScript 2015 spec objects do preserve creation order for string and Symbol keys, so traversal of an object with ie only string keys would yield keys in order of insertion)
As a note, properties order in objects weren’t guaranteed at all before ES2015. 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.
-
7The behavior of integer keys isn't consistent across all browsers. Some older browsers iterate integer keys in insertion order (with the string keys) and some in ascending order.Dave Dopson– Dave Dopson12/29/2019 00:13:50Commented Dec 29, 2019 at 0:13
-
6@DaveDopson - Right -- obsolete browsers don't follow the current specification, because they aren't updated.T.J. Crowder– T.J. Crowder01/02/2020 08:46:21Commented Jan 2, 2020 at 8:46
-
1Is "Integer keys" correct? Based on my limited tests only whole number keys / non-negative integer keys are sorted in ascending order.cementblocks– cementblocks12/06/2021 18:48:38Commented Dec 6, 2021 at 18:48
-
2@cementblocks "integer keys" is a bit broad. It's really the "numeric array keys" of an object, which are basically keys between 0 (inclusive) and (2^32) - 1 (exclusive) that will be iterated in insertion order. So negative numbers, non-integers, and numbers equal to
(2**32) - 1
or higher will be iterated in insertion order, similar to string keys :)Nick Parsons– Nick Parsons10/13/2023 13:00:13Commented Oct 13, 2023 at 13:00 -
JSON does not decode to a Map.Quolonel Questions– Quolonel Questions01/29/2025 00:09:37Commented Jan 29 at 0:09
YES (but not always insertion order).
Most Browsers iterate object properties as:
- Positive integer keys in ascending order (and strings like "1" that parse as ints)
- String keys, in insertion order (ES2015 guarantees this and all browsers comply)
- Symbol names, in insertion order (ES2015 guarantees this and all browsers comply)
Some older browsers combine categories #1 and #2, iterating all keys in insertion order. If your keys might parse as integers, it's best not to rely on any specific iteration order.
Current Language Spec (since ES2015) insertion order is preserved, except in the case of keys that parse as positive integers (eg "7" or "99"), where behavior varies between browsers. For example, Chrome/V8 does not respect insertion order when the keys are parse as numeric.
Old Language Spec (before ES2015): Iteration order was technically undefined, but all major browsers complied with the ES2015 behavior.
Note that the ES2015 behavior was a good example of the language spec being driven by existing behavior, and not the other way round. To get a deeper sense of that backwards-compatibility mindset, see http://code.google.com/p/v8/issues/detail?id=164, a Chrome bug that covers in detail the design decisions behind Chrome's iteration order behavior. Per one of the (rather opinionated) comments on that bug report:
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.
-
2@BenjaminGruenbaum - that was my point exactly. As of 2014 all the major vendors had a common implementation and thus the standards will eventually follow (ie, in 2015).Dave Dopson– Dave Dopson10/01/2015 02:01:03Commented Oct 1, 2015 at 2:01
-
5By the way: React
createFragment
API already relies on this... 🤔mik01aj– mik01aj07/04/2016 15:44:17Commented Jul 4, 2016 at 15:44 -
9@BenjaminGruenbaum Your comment is false. In ES2015 the order is guaranteed only for selected methods. See answer of ftor below.Piotr Dobrogost– Piotr Dobrogost10/07/2016 15:34:59Commented Oct 7, 2016 at 15:34
-
@mik01aj wanna link the source code from React that does? (yes, I'm being lazy)Jose V– Jose V01/12/2021 05:47:00Commented Jan 12, 2021 at 5:47
-
@DaveDopson for point 1. it's only non-negative integer keys correct?Artur Carvalho– Artur Carvalho05/10/2021 14:29:41Commented May 10, 2021 at 14:29
Property order in normal Objects is a complex subject in JavaScript.
While in ES5 explicitly no order has been specified, ES2015 defined an order in certain cases, and successive changes to the specification since have increasingly defined the order (even, as of ES2020, the for-in
loop's order). Given is the following object:
const 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"
}
The order for "own" (non-inherited) properties is:
- Positive integer-like keys in ascending order
- String keys in insertion order
- Symbols in insertion order
Thus, there are three segments, which may alter the insertion order (as happened in the example). And positive integer-like keys don't stick to the insertion order at all.
In ES2015, only certain methods followed the order:
- Object.assign
- Object.defineProperties
- Object.getOwnPropertyNames
- Object.getOwnPropertySymbols
- Reflect.ownKeys
- JSON.parse
- JSON.stringify
As of ES2020, all others do (some in specs between ES2015 and ES2020, others in ES2020), which includes:
- Object.keys, Object.entries, Object.values, ...
- for..in
The most difficult to nail down was for-in
because, uniquely, it includes inherited properties. That was done (in all but edge cases) in ES2020. The following list from the linked (now completed) proposal provides the edge cases where the order is not specified:
- Neither the object being iterated nor anything in its prototype chain is a proxy, typed array, module namespace object, or host exotic object.
- Neither the object nor anything in its prototype chain has its prototype change during iteration.
- Neither the object nor anything in its prototype chain has a property deleted during iteration.
- Nothing in the object's prototype chain has a property added during iteration.
- No property of the object or anything in its prototype chain has its enumerability change during iteration.
- No non-enumerable property shadows an enumerable one.
Conclusion: Even in ES2015 you shouldn't rely on the property order of normal objects in JavaScript. It is prone to errors. If you need ordered named pairs, use Map
instead, which purely uses insertion order. If you just need order, use an array or Set
(which also uses purely insertion order).
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.
-
17Chrome implements a different order to other browsers. See code.google.com/p/v8/issues/detail?id=164Tim Down– Tim Down04/02/2011 21:17:38Commented Apr 2, 2011 at 21:17
-
9Opera 10.50 and above, as well as IE9, match Chrome's order. Firefox and Safari are now a minority (and both of them also use different orders for Objects/Arrays).gsnedders– gsnedders04/03/2011 00:03:58Commented Apr 3, 2011 at 0:03
-
1@Veverke there is explicitly no guarantee on order so one should always assume that the order is effectively random.Alnitak– Alnitak03/10/2015 14:11:24Commented Mar 10, 2015 at 14:11
-
1@Veverke No, the order is nothing like that predictable. It's implementation dependent and subject to change at any time, and could change (for example) every time your browser updates itself.Alnitak– Alnitak03/10/2015 14:15:48Commented Mar 10, 2015 at 14:15
-
4This answer is false in ES2015.Benjamin Gruenbaum– Benjamin Gruenbaum09/30/2015 18:53:20Commented Sep 30, 2015 at 18:53
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:
... each own property key
P
ofO
[the object being iterated] that is an integer index, in ascending numeric index order... each own property key
P
ofO
that is a String but is not an integer index, in property creation order... each own property key
P
ofO
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
.
As of ES2015, property order is guaranteed for certain methods that iterate over properties. but not others. Unfortunately, the methods which are not guaranteed to have an order are generally the most often used:
Object.keys
,Object.values
,Object.entries
for..in
loopsJSON.stringify
But, as of ES2020, property order for these previously untrustworthy methods will be guaranteed by the specification to be iterated over in the same deterministic manner as the others, due to to the finished proposal: for-in mechanics.
Just like with the methods which have a guaranteed iteration order (like Reflect.ownKeys
and Object.getOwnPropertyNames
), the previously-unspecified methods will also iterate in the following order:
- Numeric array keys, in ascending numeric order
- All other non-Symbol keys, in insertion order
- Symbol keys, in insertion order
This is what pretty much every implementation does already (and has done for many years), but the new proposal has made it official.
Although the current specification leaves for..in iteration order "almost totally unspecified, real engines tend to be more consistent:"
The lack of specificity in ECMA-262 does not reflect reality. In discussion going back years, implementors have observed that there are some constraints on the behavior of for-in which anyone who wants to run code on the web needs to follow.
Because every implementation already iterates over properties predictably, it can be put into the specification without breaking backwards compatibility.
There are a few weird cases which implementations currently do not agree on, and in such cases, the resulting order will continue be unspecified. For property order to be guaranteed:
Neither the object being iterated nor anything in its prototype chain is a proxy, typed array, module namespace object, or host exotic object.
Neither the object nor anything in its prototype chain has its prototype change during iteration.
Neither the object nor anything in its prototype chain has a property deleted during iteration.
Nothing in the object's prototype chain has a property added during iteration.
No property of the object or anything in its prototype chain has its enumerability change during iteration.
No non-enumerable property shadows an enumerable one.
In ES2015, it does, but not to what you might think
The order of keys in an object wasn't guaranteed until ES2015. It was implementation-defined.
However, in ES2015 it was specified. Like many things in JavaScript, this was done for compatibility purposes and generally reflected an existing unofficial standard among most JS engines (with you-know-who being an exception).
The order is defined in the spec, under the abstract operation OrdinaryOwnPropertyKeys, which underpins all methods of iterating over an object's own keys. Paraphrased, the order is as follows:
All integer index keys (stuff like
"1123"
,"55"
, etc) in ascending numeric order.All string keys which are not integer indices, in order of creation (oldest-first).
All symbol keys, in order of creation (oldest-first).
It's silly to say that the order is unreliable - it is reliable, it's just probably not what you want, and modern browsers implement this order correctly.
Some exceptions include methods of enumerating inherited keys, such as the for .. in
loop, that doesn't guarantee order according to the specification.
-
actually i test it out and yeah that is the way` js` handles array orders it sends numbers at top of the array with order for example
{99999: "John",1: "a",age: 30,696:'12312'}
will end up like { 1: "a", 696: "12312", 99999: "John", age: 30 } so mind your number indexesRman__– Rman__08/27/2023 10:55:08Commented Aug 27, 2023 at 10:55 -
FYI: this means you need to be careful generating or manipulating package.json hashes. NodeJS made
exports
conditions resolution order-dependent. This means that code that manipulates package.json could get into trouble if you're not careful! Docs: nodejs.org/api/packages.html#conditional-exportsfbartho– fbartho04/14/2025 18:55:47Commented Apr 14 at 18:55
In modern browsers you can use the Map
data structure instead of a object.
A Map object can iterate its elements in insertion order...
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.
Major Difference between Object and MAP with Example :
it's Order of iteration in loop, In Map it follows the order as it was set while creation whereas in OBJECT does not.
SEE: OBJECT
const obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
obj['1'] = "day";
console.log(obj)
**OUTPUT: {1: "day", prop1: "Foo", prop2: "Bar"}**
MAP
const myMap = new Map()
// setting the values
myMap.set("foo", "value associated with 'a string'")
myMap.set("Bar", 'value associated with keyObj')
myMap.set("1", 'value associated with keyFunc')
OUTPUT:
**1. ▶0: Array[2]
1. 0: "foo"
2. 1: "value associated with 'a string'"
2. ▶1: Array[2]
1. 0: "Bar"
2. 1: "value associated with keyObj"
3. ▶2: Array[2]
1. 0: "1"
2. 1: "value associated with keyFunc"**
-
6who still uses
var
in 2020 ?vdegenne– vdegenne11/26/2020 12:12:05Commented Nov 26, 2020 at 12:12 -
1
Just found this out the hard way.
Using React with Redux, the state container of which's keys I want to traverse in order to generate children is refreshed everytime the store is changed (as per Redux's immutability concepts).
Thus, in order to take Object.keys(valueFromStore)
I used Object.keys(valueFromStore).sort()
, so that I at least now have an alphabetical order for the keys.
For a 100% fail-safe solution you could use nested objects and do something like this:
const obj = {};
obj.prop1 = {content: "Foo", index: 0};
obj.prop2 = {content: "Bar", index: 1};
for (let i = 0; i < Object.keys(obj).length; i++)
for (const prop in obj) {
if (obj[prop].index == i) {
console.log(obj[prop].content);
break;
}
}
-
3This is O(n^2), probably not a great solution.Mark Fisher– Mark Fisher06/14/2022 13:21:55Commented Jun 14, 2022 at 13:21
-
@MarkFisher I guess that's the trade-off for being fail-safe. However, optimization was still possible here: I have added a "break". Now it is approx. (n^2)/2.keth-tex– keth-tex06/25/2022 07:38:02Commented Jun 25, 2022 at 7:38
-
2I don't see any need for a trade-off in performance. How is Drew Durham's solution, for example, which could allow you to do the same thing as here in O(n), not failsafe? Also O(n^2 / 2) is still O(n^2).Mark Fisher– Mark Fisher06/25/2022 11:25:04Commented Jun 25, 2022 at 11:25
Actually, it doesn't guarantee order, but most likely, it orders by inserting items, but in some cases the order is change prone .For instance, if you use Object. Keys and Object. Values, the results of them aren't the same in first order. Likely
A solution to save order is to save keys and use those keys to access the object in the first order.
Something like this:
MergeFlatedObjValue(obj){
const myJSONString = JSON.stringify(obj);
const regexp = /(?<!:)("[\w.]+")/g;
let matches = myJSONString.matchAll(regexp);
var MergeFlatedObjValue="";
for (const match of matches) {
var matched=match[0];
matched=matched.replace(/['"]+/g, '');
MergeFlatedObjValue+=obj[matched]+"#";
}
return MergeFlatedObjValue;
}
The actual key order can be different from the insertion order:
console.log({ 5: 5, 2: 2 })
And the result is:
{ '2': 2, '5': 5 }
So don't rely on the insertion order.
Edit: the below post was only a developer tools display issue. As pointed out by @Bergi, the iteration order is as described in other answers. I leave it here in case others find the same pitfall. For the records, my code compiles with Vite, "react": "^18.3.1"
, and I tested this in both chrome and Firefox.
Some of my code relying on the order of properties just broke. Today I made tests and found that they are now ordered like this:
- Numbers
- Caps, alphabetical order
- Lowercase, alphabetical order
Hence, after I insert my sorted properties, they are put back to this order. This holds with Object.fromEntries
and with insertion with brackets. The following code:
let test = {}
test["b"] = "insert order 1"
test["a"] = "insert order 2"
test[1] = "insert order 3"
test["B"] = "insert order 4"
test["A"] = "insert order 5"
test["C"] = "insert order 6"
console.log(test)
Prints this:
-
The property order (such as returned by
Object.keys
) is still['1', 'b', 'a', 'B', 'A', 'C']
as expected (and described in the answers above); regardless of how your devtools are rendering the console output. But yes, don't write code relying on object property order.Bergi– Bergi09/06/2024 15:39:29Commented Sep 6, 2024 at 15:39 -
You are right, its different only in print. I tested with Object.entries.map(), just like the original code did after deserializing the API call's JSON result. Then, I got no clue where the change in behavior came from, but anyways I now sort it again before inserting it in the list, instead of trusting the API call's result order. (Otherwise the API could be changed to return a list, if I had no means of sorting it.)JM Lord– JM Lord09/06/2024 17:29:44Commented Sep 6, 2024 at 17:29
-
Yes, if order is important (and not controlled by the client), the API should absolutely return an array.Bergi– Bergi09/06/2024 19:35:55Commented Sep 6, 2024 at 19:35
From the JSON standard:
An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array.
(emphasis mine).
So, no you can't guarantee the order.
-
9this is specified by the ECMAScript standard - not the JSON spec.Alnitak– Alnitak04/02/2011 21:01:23Commented Apr 2, 2011 at 21:01
-
7@Alnitak, @Iacqui: JSON only takes this from the ECMAScript specification. It is specified for JSON too, but this does not really relate to the question.Paŭlo Ebermann– Paŭlo Ebermann07/02/2011 12:57:53Commented Jul 2, 2011 at 12:57
-
Tackling the old comments above: We can now say that JSON takes this from an old ECMAScript standard. ECMAScript has evolved a lot since then. Previously it stated an object "is an unordered collection of properties", but those days are over. The order is well-definedtrincot– trincot01/21/2025 10:33:39Commented Jan 21 at 10:33
for-in
,Object.keys
) don't have to support it (officially), but there is order now. (Unofficially: Firefox, Chrome, and Edge all follow the specified order even in for-in and Object.keys, where they aren't officially required to: jsfiddle.net/arhbn3k2/1)for-in
has a defined order; I've updated this answer with the current state of play.