Предоставляет ли ES6 четко определенный порядок перечисления свойств объекта?
var o = {
'1': 1,
'a': 2,
'b': 3
}
Object.keys(o); // ["1", "a", "b"] - is this ordering guaranteed by ES6?
for(let k in o) {
console.log(k);
} // 1 2 3 - is this ordering guaranteed by ES6?
Ответ 1
Для for-in
, Object.keys
и JSON.stringify
: Нет.
Для некоторых других операций: Да, обычно.
Хотя ES6/ES2015 добавляет порядок свойств, для него не требуется, чтобы for-in
, Object.keys
или JSON.stringify
следовали этому порядку из-за устаревших проблем совместимости.
for-in
цикл повторяется в соответствии с [[Enumerate]], который [определяется как (выделено мной):
Когда внутренний метод [[Enumerate]] для O вызывается следующим шаги предприняты:
Вернуть объект Iterator (25.1.1.2), следующий метод которого повторяется над всеми строковыми ключами перечислимых свойств О. Объект Iterator должен наследоваться от% IteratorPrototype% (25.1.2). Механика и порядок перечисления свойств не указано, но должно соответствовать правилам, указанным ниже [1].
ES7/ES2016 удаляет внутренний метод [[Enumerate]] и вместо этого использует абстрактную операцию EnumerateObjectProperties, но точно так же, как [[Enumerate]], не задает никакой порядок.
А также посмотрите цитату из Object.keys
:
Если реализация определяет конкретный порядок перечисления для выражение о вступлении в силу, [...]
Это означает, что реализации НЕ обязаны определять конкретный порядок перечисления. Это было подтверждено Алленом Вирфсом-Броком, редактором проекта спецификации языка ECMAScript 2015, в сообщении, сделанном после завершения спецификации.
Другие операции, такие как Object.getOwnPropertyNames
, Object.getOwnPropertySymbols
, Object.defineProperties
и Reflect.ownKeys
, выполняются в следующем порядке для обычные объекты:
- Целочисленные индексы (если применимо) в порядке возрастания.
- Другие строковые ключи (если применимо) в порядке создания свойств.
- Символьные ключи (если применимо) в порядке создания свойств.
Это поведение определено во внутреннем методе [[OwnPropertyKeys]]. Но некоторые экзотические объекты определяют этот внутренний метод немного по-другому. Например, ловушка Proxy ownKeys
может возвращать массив в любом порядке:
console.log(Reflect.ownKeys(new Proxy({}, {
ownKeys: () => ['3','1','2']
}))); // ['3','1','2'], the integer indices are not sorted!
Ответ 2
Как описано в другом ответе, ES2015 не определяет порядок перечисления для (очень часто используемых) итерационных методов свойств for-in
, Object.keys
и JSON.stringify
, тогда как он определяет методы перечисления для других методов, таких как Reflect.ownKeys
. Однако это (вероятно, скоро) больше не будет иметь место.
Как многие, вероятно, наблюдали в своем опыте работы с JS и в комментариях, хотя порядок итераций свойств не гарантируется спецификацией для этих методов, каждая реализация почти всегда выполняет итерацию в одном и том же детерминированном порядке. В результате есть предложение изменить спецификацию, чтобы сделать это поведение официальным:
Указание порядка перечисления for-in (Этап 3)
С этим предложением, в большинстве случаев, for..in
, Object.keys
/values
/entries
и JSON.stringify
гарантированно будут повторяться в следующем порядке:
(1) Ключи числового массива
(2) не символьные ключи в порядке вставки
(3) символьные клавиши в порядке вставки
Это тот же порядок, что и для Reflect.ownKeys
и других методов, которые уже гарантированно повторяют этот путь.
текст спецификации довольно прост: EnumerateObjectProperties
, проблемный абстрактный метод, вызванный for..in
и т.д., Порядок которого раньше не указывался, теперь будет вызывать [[OwnPropertyKeys]]
, который является внутренним методом, для которого указан порядок итераций.
Есть несколько странных случаев, с которыми реализации в настоящее время не согласуются, и в таких случаях результирующий порядок будет по-прежнему не определен, но таких случаев немного и они далеко друг от друга.