Властивості сортування у Javascript порушені


15

Мені потрібно провести цикл через об’єкт 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

Що означає:

  • (тест1), якщо ключі нижче 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 поводиться інакше, ніж три часові позначки, упорядковані однаково.


я гадаю, як обчислюється хеш-код, але це не реальна відповідь на ваше запитання.
Маріо Вернарі

1
Я не думаю, що це порушено в реальному розмовному значенні цього слова, вони не гарантують, що значення будуть повторені на замовлення, оскільки воно працює довільно, як ви можете перевірити developer.mozilla.org/en-US/docs/Web / JavaScript / Довідка /… "Примітка: for ... in не слід використовувати для ітерації над масивом, де важливий порядок індексів." Вони гарантують лише ітерацію кожного елемента колекції. Щось на зразок forEach насправді враховує порядок, переміщуючи елементи у порядку зростання ecma-international.org/ecma-262/5.1/#sec-15.4.4.18
Mr.Toxy

Для запису можна побачити проблему безпосередньо, увійшовши в систему test1та test2. Я думаю, що "питання" - від ключового кешування у виконанні V8 специфікації.
Seblor

Більше того, що нижче 2 ^ 32 назва вашого ресурсу збігається за збігом обставин, подібним до внутрішніх посилань на властивості. Ви можете і не повинні покладатися на порядок властивостей об'єкта, оскільки за визначенням вони не впорядковані і можуть містити властивості, властиві об'єкту. Завжди киньте / картайте ваш об’єкт у масив, сортуйте масив, а потім проведіть його, якщо важливий порядок.
user3154108

1
@ Mr.Toxy Це тому, що ці властивості 4294968333і 4294968111більше, ніж 2 ** 32(що є 4294967296). Таким чином, вони не мають масивів показників, тому вони повторюються в порядку створення властивостей, а не в порядку зростання чисел - саме це і роблять у скрипці, як і очікувалося. (див. мою відповідь)
Окреме виконання

Відповіді:


4

Це очікується. Згідно специфікації , метод , який перебирає властивості, OrdinaryOwnPropertyKeys, робить:

  1. Для кожного власного ключа P з O, який є індексом масиву , у порядку зростання числового індексу виконайте

    а. Додайте P як останній елемент клавіш.

  2. Для кожного власного ключа P з O, який є String, але не є індексом масиву, у зростаючому хронологічному порядку створення властивості виконайте

    а. Додайте P як останній елемент клавіш.

Висхідний числовий порядок застосовується лише для властивостей, які є індексами масиву.

Отже, що таке "індекс масиву"? Подивіться :

Цілочисельний індекс - це цільовий рядок властивості, що є канонічним числовим рядком (див. 7.1.21) і числове значення якого є або +0, або додатне ціле число ≤ 2 ^ 53 - 1. Індекс масиву - це цілий індекс, чисельний чисельний значення i знаходиться в діапазоні +0 ≤ i <2 ^ 32 - 1.

Отже, числові властивості, що перевищують 2 ^ 32, не є показниками масиву, а тому ітераторами в порядку створення властивостей. Тим НЕ менше, числові властивості, які менше , ніж 2^32 в indicies масиву, і ітерації в висхідному числовому порядку.

Так, наприклад:

1: Індекс масиву буде повторений чисельно

10: Індекс масиву буде повторений чисельно

4294968111: Більше 2 ** 32, буде повторене після завершення показників масиву в порядку створення властивостей

9999999999999: Більше 2 ** 32, буде повторене після завершення показників масиву в порядку створення властивостей

Крім того , майте на увазі , що, всупереч поширеній думці, порядок властивостей ітерація буде гарантовано специфікацією , а також, завдяки пропозицією про-в ітерація , яка є 4 -й стадії.


2

Це пов'язано з тим, як проходять ключі від об'єкта.

Відповідно до специфікацій ES6, це повинно бути:

9.1.12 [[OwnPropertyKeys]] ( )

When the [[OwnPropertyKeys]] internal method of O is called the following steps are taken:

    Let keys be a new empty List.
    For each own property key P of O that is an integer index, in ascending numeric index order
        Add P as the last element of keys.
    For each own property key P of O that is a String but is not an integer index, in property creation order
        Add P as the last element of keys.
    For each own property key P of O that is a Symbol, in property creation order
        Add P as the last element of keys.
    Return keys.

http://www.ecma-international.org/ecma-262/6.0/#sec-fficial-object-internal-methods-and-internal-slots-ownpropertykeys

Це означає, що якщо значення ключа залишається таким же, якщо перетворюється на непідписане 53-бітове число і назад, воно трактується як цілий індекс, який сортується у порядку зростання чисел.

Якщо це не вдалося, він трактується як рядовий ключ, який упорядковується так, як вони були додані до об'єкта.

Привід тут полягає в тому, що всі основні браузери ще не дотримуються цієї специфікації та використовують індекс масиву, який обмежується додатним числом до 2 ^ 32-1. Так що все, що перевищує цю межу, є фактично ключовим рядком.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.