9

Гарантирует ли JavaScript порядок свойств объекта?

14

Я создал объект следующим образом:

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

Будет ли получившийся объект всегда выглядеть так:

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

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

5 ответ(ов)

3

ДА (но не всегда в порядке вставки).

Большинство браузеров перебирают свойства объектов в следующем порядке:

  1. Положительные целочисленные ключи в порядке возрастания (и строки, такие как "1", которые интерпретируются как целые числа)
  2. Строковые ключи в порядке вставки (это гарантировано спецификацией ES2015, и все браузеры это поддерживают)
  3. Имена символов в порядке вставки (также гарантировано ES2015 и поддерживается всеми браузерами)

Некоторые старые браузеры комбинируют категории #1 и #2, перебирая все ключи в порядке вставки. Если ваши ключи могут быть интерпретированы как целые числа, лучше не полагаться на какой-либо конкретный порядок перебора.

Текущая спецификация языка (с ES2015) сохраняет порядок вставки, за исключением случаев, когда ключи интерпретируются как положительные целые числа (например, "7" или "99"), где поведение может варьироваться между браузерами. Например, Chrome/V8 не соблюдают порядок вставки, когда ключи интерпретируются как числовые.

Старая спецификация языка (до ES2015): Порядок перебора технически был не определен, но все основные браузеры придерживались поведения ES2015.

Заметьте, что поведение ES2015 является хорошим примером того, как спецификация языка была опирается на существующее поведение, а не наоборот. Чтобы лучше понять эту концепцию обратной совместимости, посмотрите http://code.google.com/p/v8/issues/detail?id=164, где обсуждаются решения по дизайну поведения порядка перебора в Chrome.

Цитируя один из (довольно предвзятых) комментариев к этому отчету об ошибке:

Стандарты всегда следуют за реализациями, откуда появился XHR, и Google делает то же самое, сначала реализуя Gears, а затем принимая эквивалентный функционал HTML5. Правильное решение - это официально интегрировать поведение де-факто стандарт в следующей версии спецификации ECMA.

0

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

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

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

0

Основное отличие между объектом и Map заключается в порядке итерации в цикле. В Map порядок соответствует тому, в каком он был установлен при создании, тогда как в объекте порядок не гарантируется.

Объект:

const obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
obj['1'] = "day";
console.log(obj);

Результат:

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

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

Map:

const myMap = new Map();
// Установка значений
myMap.set("foo", "значение, связанное с 'строкой'");
myMap.set("Bar", 'значение, связанное с keyObj');
myMap.set("1", 'значение, связанное с keyFunc');

console.log(myMap);

Результат:

1.    ▶0: Array[2]
1.   0: "foo"
2.   1: "значение, связанное с 'строкой'"
2.  ▶1: Array[2]
1.   0: "Bar"
2.   1: "значение, связанное с keyObj"
3.  ▶2: Array[2]
1.   0: "1"
2.   1: "значение, связанное с keyFunc"

В результате, как видно, порядок вставки сохраняется. Значения в Map будут возвращены в том порядке, в котором они были добавлены. То есть, если вам важно сохранять порядок элементов, лучше использовать Map вместо объекта.

0

Недавно я узнал это на собственном опыте.

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

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

0

Для 100% надежного решения вы можете использовать вложенные объекты и сделать что-то подобное:

const obj = {};
obj.prop1 = {content: "Foo", index: 0};
obj.prop2 = {content: "Bar", index: 1};

for (let i = 0; i < Object.keys(obj).length; i++) {
    for (const prop in obj) {
        if (obj[prop].index == i) {
            console.log(obj[prop].content);
            break;
        }
    }
}

Таким образом, вы сможете гарантировать, что ваш код корректно отобразит содержимое объектов в соответствии с его индексом.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь