Мне нужно перебрать объект JavaScript, рассматривая его как массив с пользовательскими ключами. Я знаю, что это не полностью поддерживается, поскольку свойства не имеют собственного порядка, но так как я всегда изменяю порядок свойств, я нашел этот подход простым и надежным ... до сих пор.
Проблема возникает, когда ключи представляют собой числа или строки, которые могут быть преобразованы в числа.
Когда я запускаю этот код:
var test1 = {4294966222:"A",4294966333:"A",4294966111:"A"};
var test2 = {4294968222:"A",4294968333:"A",4294968111:"A"};
for (var k in test1) {console.log(k);}
console.log("---");
for (var k in test2) {console.log(k);}
выход:
4294966111
4294966222
4294966333
---
4294968222
4294968333
4294968111
Что значит:
- (test1), если ключи меньше 2 ^ 32 (4 294 967 296), они автоматически переупорядочиваются, самые маленькие сначала
- (test2) если ключи выше 2 ^ 32, они НЕ переупорядочиваются.
Вопрос в том, почему это происходит?
Поскольку все протестированные мной браузеры (Google Chrome 79.0, Mozilla Firefox 71.0, Microsoft Edge 44.18362, Internet Explorer 11.535) согласны с этим выводом, должна быть какая-то официальная спецификация.
Обновить
Я проверил много цифр, прежде чем выяснил, что это пороговый уровень. Мне показалось странным, что последовательность 2,3,1 ведет себя не так, как три метки времени, упорядоченные одинаково.
источник
test1
иtest2
. Я думаю, что «проблема» связана с ключевым кешированием в реализации спецификации V8.4294968333
и4294968111
больше, чем2 ** 32
(что есть4294967296
). Таким образом, они не являются указателями на массивы, поэтому они повторяются в порядке создания свойств, а не в порядке возрастания чисел, что, как и ожидалось, является именно тем, что они делают в скрипте. (см. мой ответ)Ответы:
Это ожидается. В соответствии со спецификацией , метод, который перебирает свойства
OrdinaryOwnPropertyKeys
, делает:Восходящий числовой порядок применяется только для свойств, которые являются указателями массива.
Итак, что такое «индекс массива»? Посмотри :
Таким образом, числовые свойства, которые больше чем 2 ^ 32, не являются указателями массива, и поэтому повторяются в порядке создания свойств. Тем не менее, числовые свойства, которые меньше , чем
2^32
в indicies массива, и итерации в восходящем числовом порядке.Так, например:
1
: Индекс массива, будет повторяться численно10
: Индекс массива, будет повторяться численно4294968111
: Больше2 ** 32
, будет повторяться после завершения индикации массива в порядке создания свойства9999999999999
: Больше2 ** 32
, будет повторяться после завершения индикации массива в порядке создания свойстваКроме того , имейте в виду , что, вопреки распространенному мнению, порядок свойств итерация будет гарантировано спецификацией , а также, благодаря предложению о-в итерация , которая является 4 -й стадии.
источник
Это связано с тем, как они проходят ключи объекта.
Согласно спецификации ES6 это должно быть:
http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
Это означает, что если значение ключа остается неизменным, если оно преобразовано в 53-разрядное число без знака и обратно, оно обрабатывается как целочисленный индекс, который сортируется в порядке возрастания чисел .
Если это не удается, он обрабатывается как строковый ключ, который упорядочен так, как он был добавлен к объекту.
Подвох в том, что все основные браузеры еще не следуют этой спецификации и вместо этого используют индекс массива, который ограничен положительным числом до . Так что все, что выше этого предела, на самом деле является строковым ключом.
источник