Как выполнить итерацию свойств объекта javascript в том порядке, в котором они были написаны

Я обнаружил ошибку в моем коде, который, я надеюсь, решит с минимальными усилиями рефакторинга. Эта ошибка возникает в браузерах Chrome и Opera. Проблема:

var obj = {23:"AA",12:"BB"};
//iterating through obj properties
for(i in obj)
  document.write("Key: "+i +" "+"Value: "+obj[i]);

Вывод в FF, IE Ключ: 23 Значение: AA Ключ: 12 Значение: BB

Вывод в Opera и Chrome (Неверно)
Ключ: 12 Value BB
Ключ: 23 Значение AA

Я попытался создать обратный упорядоченный объект, подобный этому

var obj1={"AA":23,"BB":12};
for(i in obj1)
  document.write("Key: "+obj[i] +" "+"Value: "+i);

Однако вывод одинаков. Есть ли способ получить для всего браузера такое же поведение с небольшими изменениями?

Ответ 1

Нет. Свойства объекта JavaScript не имеют встроенного порядка. Это полная удача в том, какой порядок работает цикл for...in.

Если вы хотите заказать, вам придется использовать массив:

var map= [[23, 'AA'], [12, 'BB']];
for (var i= 0; i<map.length; i++)
    document.write('Key '+map[i][0]+', value: '+map[i][1]);

Ответ 2

Я думаю, вы найдете единственный надежный способ сделать это: использовать массив, а не ассоциативный массив, например:

var arr = [{key:23,val:"AA"},{key:12,val:"BB"}];
for(var i=0; i<arr.length; i++)
  document.write("Key: "+arr[i].key +" "+"Value: "+arr[i].val);

Ответ 3

@bobince прав, объекты не хранят метаданные порядка.

В моем случае не было смысла проводить рефакторинг в массив, поэтому я предлагаю другое решение: создайте массив с вашим порядком и используйте его для отображения свойств вашего объекта по порядку:

const obj = {
    'r': '#f00',
    'g': '#0f0',
    'b': '#00f',
};
const objMap = ['b','r','g'];

objMap.map((key, index) => {
    console.log('array index: ${index}');
    console.log('object index: ${key}');
    console.log('object property: ${obj[key]}\n');
});

Выход:

array index: 0
object index: b
object property: #00f

array index: 1
object index: r
object property: #f00

array index: 2
object index: g
object property: #0f0

Ответ 4

Я не получил ваш результат, когда идентификаторы свойств объекта были алфавитными. IE8, FF5, Chrome 12 и Opera 9.8 сохранили порядок создания, т.е.

Ключ: AA Значение: 23 Ключ: BB Значение: 12

Именно тогда, когда идентификаторы были номерами, результаты соответствовали вашим: -

IE8, FF5 → Ключ: 23 Значение: Ключ: 12 Значение: BB

Opera, Chrome → Key: 12 Значение: BB Key: 23 Значение: AA

Opera и Chrome хранятся в обратном порядке для создания, потому что 12 меньше 23, поэтому, если вы используете вместо этого, скажите: -

var obj = {2:"AA",12:"BB"};

то вы получите этот результат для всех 4 браузеров: -

Ключ: 2 Значение: Ключ: 12 Значение: BB

Таким образом, использование чисел в качестве идентификаторов вызывает несоответствие. Если идентификаторы являются алфавитными, то оба заказа на создание и сохраненные свойства одинаковы для 4-х браузеров. Это несмотря на правила ECMA, что сохраненный порядок не должен быть связан с порядком создания.

Если строковые идентификаторы являются числовыми, например. "23" и "12", то Opera и Chrome рассматривают их как числа и снова меняют порядок создания, поэтому тип также не разрешен. Типы "23a" в порядке, как и "a23".

Чтобы ответить на ваш вопрос, используйте нечисловые идентификаторы строк, и поведение будет одинаковым в четырех браузерах (и, возможно, во всех браузерах).