Если я создам такой объект:
var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
Будет ли результирующий объект всегда выглядеть так?
{ prop1 : "Foo", prop2 : "Bar" }
То есть будут ли свойства в том же порядке, что и я?
Если я создам такой объект:
var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
Будет ли результирующий объект всегда выглядеть так?
{ prop1 : "Foo", prop2 : "Bar" }
То есть будут ли свойства в том же порядке, что и я?
Порядок итераций для объектов соответствует определенному набору правил начиная с ES2015, но он (не всегда) соответствует порядку вставки. Проще говоря, порядок итераций представляет собой комбинацию порядка вставки для строковых ключей и возрастающего порядка для числовых ключей:
// key order: 1, foo, bar
const obj = { "foo": "foo", "1": "1", "bar": "bar" }
Использование массива или объекта Map
может быть лучшим способом для достижения этой цели. Map
имеет некоторые сходства с Object
и гарантирует, что ключи будут повторяться в порядке вставки без исключения:
Ключи в Map упорядочены, а ключи, добавленные к объекту - нет. Таким образом, при итерации по нему объект Map возвращает ключи в порядке вставки. (Обратите внимание, что в спецификациях ECMAScript 2015 объекты сохраняют порядок создания для строковых и символьных ключей, поэтому обход объекта с т.е. только строковыми ключами даст ключи в порядке вставки)
Как примечание, порядок свойств в объектах не был гарантирован до ES2015. Определение объекта из ECMAScript Third Edition (pdf):
4.3.3 Объект
Объект является членом Тип объекта. Это неупорядоченный набор свойств, каждый из которых содержит примитивное значение, объект или функция. Функция хранится в Свойство объекта называется метод.
ДА (для нецелых ключей) - ответ выше НЕПРАВИЛЬНЫЙ!
Текущая языковая спецификация (начиная с ES2015) порядок вставки сохраняется, за исключением случаев, когда ключи разбираются как целые числа (например, "7" или "99"), где поведение варьируется в зависимости от браузера. Например, Chrome/V8 не учитывает порядок вставки, когда ключи анализируются как числовые.
Спецификация старого языка (до ES2015). Порядок итераций был технически не определен, но все основные браузеры соответствовали поведению ES2015.
Обратите внимание, что поведение ES2015 было хорошим примером языковой спецификации, обусловленной существующим поведением, а не наоборот. Чтобы получить более глубокое представление об этом образе мышления с обратной совместимостью, см. http://code.google.com/p/v8/issues/detail?id=164, ошибку Chrome, которая подробно описывает решения по разработке поведения порядка итерации Chrome. За один из (довольно самоуверенных) комментариев к этому сообщению об ошибке:
Стандарты всегда следуют реализациям, то есть откуда XHR, и Google делает то же самое, внедряя Gears, а затем охватывает эквивалентную функциональность HTML5. Правильное решение состоит в том, чтобы иметь ECMA формально включить стандартное поведение де-факто в следующую версию спецификации.
Порядок свойств в обычных объектах является сложным объектом в Javascript.
Хотя в ES5 явно не указан порядок, ES2015 имеет порядок в определенных случаях. Это следующий объект:
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},
});
Это приводит к следующему порядку (в некоторых случаях):
Object {
0: 0,
1: "1",
2: "2",
b: "b",
a: "a",
m: function() {},
Symbol(): "sym"
}
Таким образом, существует три сегмента, которые могут изменить порядок вставки (как это было в примере). И целые ключи не придерживаются порядка вставки.
Вопрос в том, для каких методов этот порядок гарантирован в спецификации ES2015?
Следующие способы гарантируют заказ:
Следующие методы/циклы не гарантируют никакого порядка:
Вывод: даже в ES2015 вы не должны полагаться на порядок свойств обычных объектов в Javascript. Он подвержен ошибкам. Вместо этого используйте Map
.
Во время записи большинство браузеров возвращали свойства в том же порядке, в каком они были вставлены, но это явно не гарантированное поведение, поэтому на него не следует полагаться.
Спецификация ECMAScript говорила:
Механика и порядок перечисления свойств... не указаны.
Однако в ES2015 и более поздних нецелых ключах будут возвращены в порядке вставки.
Весь этот ответ находится в контексте соответствия спецификации, а не того, что движок делает в определенный момент или исторически.
Актуальный вопрос очень расплывчатый.
свойства будут в том же порядке, что я добавил их
В каком контексте?
Ответ: это зависит от ряда факторов. В общем, нет.
Здесь вы можете рассчитывать на порядок ключей свойств для простого Objects
:
Object.getOwnPropertyNames()
, Reflect.ownKeys()
, Object.getOwnPropertySymbols(O)
Во всех случаях эти методы включают в себя неперечислимые ключи свойств и ключи заказа, указанные в [[OwnPropertyKeys]]
(см. ниже). Они отличаются типом ключевых значений, которые они включают (String
и/или Symbol
). В этом контексте String
содержит целочисленные значения.
Object.getOwnPropertyNames(O)
Возвращает O
собственные String
свойства с ключом (имена свойств).
Reflect.ownKeys(O)
Возвращает O
собственные String
- и Symbol
свойства с ключами.
Object.getOwnPropertySymbols(O)
Возвращает O
собственные Symbol
свойства .
[[OwnPropertyKeys]]
Порядок по существу: целочисленный Strings
в порядке возрастания, нецелоподобный Strings
в порядке создания, символы в порядке создания. В зависимости от того, какая функция вызывает это, некоторые из этих типов могут не включаться.
Специфическим языком является то, что ключи возвращаются в следующем порядке:
... каждый собственный ключ свойства
P
O
[объект, который повторяется], который является целым индексом, в порядке возрастания числового индекса... каждый собственный ключ свойства
P
ofO
, который является строкой, но не является целым индексом, в порядке создания свойства... каждый собственный ключ свойства
P
ofO
, который является символом в порядке создания свойства
Map
Если вам интересны упорядоченные карты, вы должны использовать тип Map
, введенный в ES2015, а не простой Objects
.
В современных браузерах вы можете использовать структуру данных Map
вместо объекта.
Объект Map может перебирать свои элементы в порядке вставки...
Порядок ключей в объекте не гарантировался до ES2015. Это было определено реализацией.
Тем не менее, в ES2015 в был указан. Как и многие вещи в JavaScript, это было сделано в целях совместимости и, как правило, отражало существующий неофициальный стандарт среди большинства движков JS (за исключением, что вы знаете кто).
Порядок определяется в спецификации в рамках абстрактной операции OrdinaryOwnPropertyKeys, которая лежит в основе всех методов итерации по собственным ключам объекта. Перефразируя, порядок выглядит следующим образом:
Все целочисленные индексные ключи (например, "1123"
, "55"
и т.д.) В порядке возрастания номеров.
Все строковые ключи, которые не являются целочисленными индексами, в порядке создания (самый старый-первый).
Все символьные клавиши в порядке создания (сначала самые старые).
Глупо говорить, что порядок ненадежен - он надежен, просто, вероятно, он не тот, который вам нужен, и современные браузеры правильно его реализуют.
Некоторые исключения включают методы перечисления унаследованных ключей, такие как цикл for .. in
. Петля for .. in
не гарантирует порядок согласно спецификации.
Как утверждали другие, у вас нет гарантии относительно порядка, когда вы перебираете свойства объекта. Если вам нужен упорядоченный список нескольких полей, я предложил создать массив объектов.
var myarr = [{somfield1: 'x', somefield2: 'y'},
{somfield1: 'a', somefield2: 'b'},
{somfield1: 'i', somefield2: 'j'}];
Таким образом, вы можете использовать регулярный цикл и иметь порядок вставки. Затем вы можете использовать метод сортировки массива, чтобы отсортировать его в новом массиве, если это необходимо.
Просто выяснил это трудным путем.
Используя React с Redux, контейнер состояний, ключи которого я хочу пройти для генерации дочерних элементов, обновляется каждый раз при изменении хранилища (согласно концепции неизменяемости Redux).
Таким образом, чтобы взять Object.keys(valueFromStore)
я использовал Object.keys(valueFromStore).sort()
, так что теперь у меня по крайней мере теперь есть алфавитный порядок для ключей.
Начиная с ES2015, порядок свойств гарантирован для определенных методов, которые перебирают свойства. но не другие. К сожалению, методы, порядок которых не гарантирован, обычно используются чаще всего:
Object.keys
, Object.values
, Object.entries
for..in
JSON.stringify
Но вскоре (возможно, в ES2021) порядок свойств для этих методов будет гарантирован итерацией итерироваться таким же детерминированным образом, как и другие, благодаря предложению stage 3: Порядок перечисления в порядке.
Как и в случае методов с гарантированным порядком итераций (например, Reflect.ownKeys
и Object.getOwnPropertyNames
), ранее неуказанные методы также будут выполнять итерацию в следующем порядке:
Это то, что почти во всех реализациях уже сделано, но новое предложение сделает его официальным.
Хотя текущая спецификация оставляет для… в итерационном порядке "почти полностью неопределенную, реальные движки имеют тенденцию быть более последовательными:"
Отсутствие специфичности в ECMA-262 не отражает реальность. В ходе дискуссий, проходивших много лет назад, разработчики заметили, что существуют некоторые ограничения на поведение for-in, которым должен следовать любой, кто хочет запускать код в Интернете.
Поскольку каждая реализация уже предсказуемо перебирает свойства, ее можно вставить в спецификацию, не нарушая обратной совместимости.
Есть несколько странных случаев, с которыми реализации в настоящее время не согласуются, и в таких случаях результирующий порядок будет по-прежнему не определен. Для заказа недвижимости должно быть гарантировано:
Ни повторяемый объект, ни что-либо в его цепочке прототипов не является прокси, типизированным массивом, объектом пространства имен модуля или экзотическим объектом хоста.
Ни у объекта, ни у чего-либо в его цепочке прототипов нет изменений прототипа во время итерации.
Ни у объекта, ни у чего-либо в его цепочке прототипов нет свойства, удаленного во время итерации.
Ничто в цепочке прототипов объекта не имеет свойства, добавленного во время итерации.
Ни одно свойство объекта или чего-либо в его цепочке прототипов не может изменить свою перечислимость во время итерации.
Никакое не перечисляемое свойство не затеняет перечислимое.
Из стандарта JSON:
Объект представляет собой массив неупорядоченный, содержащий ноль или несколько пар имя/значение, где имя - это строка, а значение - это строка, число, логическое значение, нуль, объект или массив.
(основное внимание).
Итак, нет, вы не можете гарантировать заказ.