Гарантирует ли JavaScript порядок свойств объекта? - PullRequest
542 голосов
/ 03 апреля 2011

Если я создаю объект, подобный этому:

var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";

Будет ли результирующий объект всегда выглядеть так?

{ prop1 : "Foo", prop2 : "Bar" }

То есть будут ли свойствабыть в том же порядке, в котором я их добавил?

Ответы [ 10 ]

405 голосов
/ 03 апреля 2011

Нет, порядок свойств в объектах не гарантируется в JavaScript;вам нужно использовать Array.

Определение объекта из ECMAScript Third Edition (pdf) :

4.3.3 Объект

Объект является членом типа Object. Это неупорядоченная коллекция свойств , каждое из которых содержит примитивное значение, объект или функцию.Функция, хранящаяся в свойстве объекта, называется методом.

Начиная с ECMAScript 2015 , использование Map объекта может быть альтернативой.Map имеет некоторые общие черты с Object и гарантирует порядок ключей :

Карта выполняет итерации своих элементов в порядке вставки, тогда как порядок итераций для объектов не указывается.

159 голосов
/ 21 апреля 2014

ДА (для нецелых ключей) - ответ выше НЕПРАВИЛЬНЫЙ!

Текущая спецификация языка (начиная с 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 формально включить стандартное поведение де-факто в следующую версию спецификации.

66 голосов
/ 06 июля 2016

Порядок свойств в обычных объектах - сложный объект в 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"
}
  1. целочисленные ключи в порядке возрастания
  2. обычные ключи в порядке вставки
  3. Символы в порядке вставки

Таким образом, есть три сегмента, которые могут изменить порядок вставки (как это произошло в примере).И целочисленные ключи вообще не придерживаются порядка вставки.

Вопрос в том, для каких методов этот порядок гарантирован в спецификации ES2015?

Следующие методы гарантируют порядокпоказано:

  • Object.assign
  • Object.defineProperties
  • Object.getOwnPropertyNames
  • Object.getOwnPropertySymbols
  • Reflect.ownKeys

Следующие методы / циклы гарантируют отсутствие заказа вообще:

  • Object.keys
  • for..in
  • JSON.parse
  • JSON.stringify

Вывод: даже в ES2015 не следует полагаться на порядок свойств обычных объектов в Javascript.Это склонно к ошибкам.Вместо этого используйте Map.

66 голосов
/ 03 апреля 2011

На момент написания статьи большинство браузеров возвращали свойства в том же порядке, в котором они были вставлены, но это явно не гарантированное поведение, поэтому на него не следует полагаться.

ECMAScriptспецификация используется для обозначения:

Механизм и порядок перечисления свойств ... не указан.

Однако в ES2015 и более поздних нецелых ключахбудет возвращен в порядке вставки.

42 голосов
/ 22 августа 2015

Весь этот ответ находится в контексте соответствия спецификации, а не того, что делает какой-либо двигатель в определенный момент или исторически.

Как правило, нет

Фактический вопрос очень расплывчатый.

свойства будут в том же порядке, в котором я их добавил

В каком контексте?

Ответ: это зависит от ряда факторов. В общем, нет .

Иногда да

Здесь можно рассчитывать на порядок ключей свойства для простого Objects:

  • ES2015-совместимый двигатель
  • Собственные свойства
  • 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 в порядке создания, символы в порядке создания. В зависимости от того, какая функция вызывает это, некоторые из этих типов могут не включаться.

Конкретным языком является то, что ключи возвращаются в следующем порядке:

  1. ... каждый собственный ключ свойства P из O [итерируемый объект], который является целочисленным индексом, в порядке возрастания числового индекса

  2. ... каждый собственный ключ свойства P из O, который является строкой, но не является целочисленным индексом, в порядке создания свойств

  3. ... каждый собственный ключ свойства P из O, который является символом, в порядке создания свойств

Map

Если вас интересуют заказанные карты, вам следует рассмотреть возможность использования типа Map, представленного в ES2015, вместо простого Objects.

12 голосов
/ 02 июня 2015

В современных браузерах вы можете использовать структуру данных Map вместо объекта.

Developer mozilla> Map

Объект Map может выполнять итерации своих элементов в порядке вставки ...

6 голосов
/ 13 февраля 2019

В ES2015 это так, но не так, как вы думаете

Порядок ключей в объекте не гарантировался до ES2015. Это было определено реализацией.

Однако в ES2015 в было указано . Как и многие другие вещи в JavaScript, это было сделано в целях совместимости и, как правило, отражало существующий неофициальный стандарт среди большинства движков JS (за исключением, вы знаете, кто).

Порядок определяется в спецификации под абстрактной операцией OrdinaryOwnPropertyKeys , которая лежит в основе всех методов итерации по собственным ключам объекта. Перефразируя, порядок выглядит следующим образом:

  1. Все целочисленные индексы ключи (такие как "1123", "55" и т. Д.) В порядке возрастания чисел.

  2. Все строковые ключи, которые не являются целочисленными индексами, в порядке создания (самый старый-первый).

  3. Все символьные клавиши в порядке их создания (сначала самые старые).

Глупо утверждать, что порядок ненадежен - он надежен, скорее всего, он не тот, который вам нужен, и современные браузеры правильно его реализуют.

Некоторые исключения включают методы перечисления унаследованных ключей, такие как цикл for .. in. Петля for .. in не гарантирует порядок в соответствии со спецификацией.

5 голосов
/ 27 января 2015

Как уже говорили другие, у вас нет гарантии относительно порядка, когда вы перебираете свойства объекта. Если вам нужен упорядоченный список из нескольких полей, я предложил создать массив объектов.

var myarr = [{somfield1: 'x', somefield2: 'y'},
{somfield1: 'a', somefield2: 'b'},
{somfield1: 'i', somefield2: 'j'}];

Таким образом, вы можете использовать обычный цикл for и иметь порядок вставки. Затем вы можете использовать метод сортировки Array, чтобы при необходимости отсортировать его в новый массив.

3 голосов
/ 02 февраля 2019

Только что выяснил трудный путь.

Использование React с Redux, контейнер состояний, ключи которого я хочу просмотреть для генерации потомков, обновляется при каждом изменении хранилища (согласно концепциям неизменяемости Redux).

Таким образом, чтобы взять Object.keys(valueFromStore), я использовал Object.keys(valueFromStore).sort(), чтобы у меня по крайней мере теперь был алфавитный порядок клавиш.

0 голосов
/ 03 апреля 2011

Из стандарта JSON :

Объект - это неупорядоченный набор из нуля или более пар имя / значение, где имя - это строка, а значение - строка, число, логическое значение, ноль, объект или массив.

(выделено мое).

Итак, нет, вы не можете гарантировать заказ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...