В JS объекты были «неупорядоченными» вплоть до ES5. Начиная с ES6 порядок обхода свойств объекта стал предсказуемым.
Сначала все неотрицательные целочисленные ключи меньше 2^32, по возрастанию (например, '1', '79' и т. д.). Как правило, это все валидные индексы массива (неотрицательные числа до 2^32).
Внимание: '05' целочисленным ключом считаться не будет — целое число, полученное при разборе, даёт другое строковое представление.
Затем все строковые ключи в порядке вставки (в том порядке, в котором их добавляли в объект).
Сюда же попадут числовые строки, не подошедшие под первый пункт, и числа с плавающей точкой.
И наконец свойства, имена которых являются символами, — в том порядке, в котором их добавляли в объект.
Если порядок перечисления важен, всегда можно взять Map: он гарантирует сохранение порядка вставки.
Обратите внимание: для цикла for in порядок перечисления определён не так строго, как для функций выше, но обычно собственные свойства перечисляются в описанном порядке.
Так как for in перечисляет ещё и свойства из цепочки прототипов, после собственных свойств он пойдёт вверх по цепочке прототипов, перечисляя свойства каждого объекта-прототипа в том же порядке, что описан выше.
Если свойство уже было перечислено, любое свойство с тем же именем перечислено не будет.
Свойство не будет перечислено, даже если перечисляемое свойство с таким же именем уже было рассмотрено.