Object properties do have a certain order, differing from insertion order. It's described in the ECMAScript 2015 Language Specification:
9.1.12 [[OwnPropertyKeys]] ( )
When the [[OwnPropertyKeys]] internal method of O is called the following steps are taken:
- Let keys be a new empty List.
- For each own property key P of O that is an integer index, in ascending numeric index order
a. Add P as the last element of keys.
- For each own property key P of O that is a String but is not an integer index, in property creation order
a. Add P as the last element of keys.
- For each own property key P of O that is a Symbol, in property creation order
a. Add P as the last element of keys.
- Return keys.
In the above, the properties are defined as the List keys. Then, when a property that is an integer is encountered, it is added to List keys in ascending numeric order, thus leading to 3, 5, 8 you observe.
If you want ordered keys and value pairs that respects order based on insertion, you must use something that respects order, such as an ES6 Map
. Per the documentation:
A Map object iterates its elements in insertion order — a for...of
loop returns an array of [key, value]
for each iteration.
Here's an example:
const obj = new Map([
[5, "test 1"],
[3, "test 2"],
[8, "test 3"]
]);
for(let [key, value] of obj) {
console.log(key, value);
}
First, you pass an array of arrays to the constructor. The Map
constructor takes in an iterable, and uses the subarrays as key and value pairs. The Map
essentially looks like this:
+-----+----------+
| Key | Value |
+-----+----------+
| 5 | "test 1" |
| 3 | "test 2" |
| 8 | "test 3" |
+-----+----------+
Next you use a for...of
loop to iterate over the Map
. As noted in the documentation, an array of [key, value]
is returned by the iterator so you can use array destructuring. Thus, key
and value
hold the values of the keys and values of the Map
respectively, and logging them provides the desired, ordered result.