Подтвердить что ты не робот

Хром переупорядочивает ключи объекта, если число, это нормально/ожидается

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

Значение JSON может быть:

{
  "7": ["9149", "9139", "10455", "17208"],
  "7.5": ["9140", "9150", "10456", "17209"],
  "8": ["2684", "9141", "10457", "17210"],
  "8.5": ["9142", "10444", "10458", "17211"],
  "9": ["2685", "9143", "10459", "17212"],
  "9.5": ["10443", "9144", "10460", "17213"]
}

..., который увеличивает размеры пополам.

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

7, 7.5, 8, 8.5 и т.д.

Но только в Chrome ключи, которые "выглядят" как круглые числа ВСЕГДА, сначала выходят из объекта, поэтому вывод цикла for for... in:

7, 8, 9, 7.5, 8.5, 9.5...

Object.keys(sizes); // ["7", "8", "9", "7.5", "8.5", "9.5"]

Вот тестовый пример: https://jsfiddle.net/wcapc46L/1/

Он влияет только на целые числа, кажется, что у Webkit/Blink есть оптимизация, которая предпочитает Свойства объекта, которые являются числовыми, возможно, это связано с Branch Prediction или любым другим.

Если вы префикс клавиш объекта с любым символом, порядок остается незатронутым и работает по назначению - FIFO

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

Любые идеи? это, вероятно, ошибка, которая будет исправлена?

отредактировать, теперь я обнаружил это как проблему в трекере ошибок v8:

http://code.google.com/p/v8/issues/detail?id=164

Похоже, что Blink не хочет исправлять это и останется единственным браузером, который это сделает.

обновить любая оптимизация хеш-таблицы webkit/blink, теперь пробилась в gecko (FF 27.0.1) - http://jsfiddle.net/9Htmq/ приводит к 7,8,9,7.5,8.5,9.5. применяя _, прежде чем ключи вернут правильный/ожидаемый порядок.

обновление 2017 Люди по-прежнему сохраняют и редактируют это так. Это НЕ влияет на Map/WeakMap, Set и т.д. (как показано в обновленном основном примере)

4b9b3361

Ответ 1

Это способ v8 обрабатывает ассоциативные массивы. Известная проблема Проблема 164, но она следует за спецификацией, поэтому помечена как "работающая по назначению". Не существует требуемого порядка для циклирования через ассоциативные массивы.

Простым обходным путем должно предшествовать числовые значения с буквами, например: 'size_7':['9149','9139'] и т.д.

Стандарт изменится в следующей спецификации ECMAScript, чтобы заставить [chrome] разработчиков изменить это.

Ответ 2

Похоже, что Chrome обрабатывает целочисленную строку, как если бы это был числовой тип при использовании в качестве имени индекса/свойства.

Я думаю, полагаясь на реализацию Javascript, чтобы сохранить порядок того, что в некоторых случаях является свойствами объекта, а в других случаях (конечно, с хромовыми) индексами массивов, является явно небезопасным подходом, и порядок перечисления, вероятно, не определен в спецификации. Я бы предложил добавить дополнительное свойство JSON, которое указывает порядок сортировки:

{
    "7":{"sortOrder":1,"data":["9149","9139","10455","17208"]},
    "7.5":{"sortOrder":2,"data":["9140","9150","10456","17209"]}
    //etc
}

Ответ 3

Они обрабатываются как строки, потому что они являются строками. Мое лучшее предложение было бы использовать ту же "точность" во всех ваших ключах.

{"7.0":["9149","9139","10455","17208"],"7.5":["9140","9150","10456","17209"],"8.0":["2684","9141","10457","17210"],"8.5":["9142","10444","10458","17211"],"9.0":["2685","9143","10459","17212"],"9.5":["10443","9144","10460","17213"]}

Итак, "8.0" вместо "8" и т.д.

Даже тогда нет гарантий, но, скорее всего, они выйдут в том же порядке.

Для лучшей гарантии выполните сортировку на основе ключей, поместив значения в массив в отсортированном порядке.

Ответ 4

При повторении свойств объекта порядок указан в спецификации ECMAScript как undefined, и на любой порядок, который вы, возможно, наблюдали в какой-либо среде, не следует полагаться. Если вам нужен заказ, используйте Array.

Ответ 5

Я не думаю, что вы можете назвать это ошибкой. Как вы сами говорите, нет никакой гарантии того, как сортируются свойства объекта.

Ответ 6

Я нашел легкую работу с использованием underscore.js

myArray = _.sortBy(myArray, function(num){ return Math.ceil(num); });

Ура! myArray вернется к правильному порядку во всех браузерах.

Ответ 7

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

<?php 
$origArray = valueReturnedFromFunction();
$preservedOrder = array_keys($origArray);
?>
<script>
var origArray = <?php echo json_encode($origArray)?>;
var preservedOrder = <?php echo json_encode($preservedOrder )?>;

for(i in preservedOrder){
    var item = origArray[i];
    ...
}
</script>