Chrome переупорядочивает ключи объекта, если они числовые, это нормально / ожидаемо - PullRequest
25 голосов
/ 06 июля 2010

Я заметил, что определенный код, который оценивает размеры обуви для сайта электронной коммерции и выводит их на экран, портит порядок в 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 ... 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 есть оптимизация, в которой предпочитает Числовые свойства объекта, возможно, это связано с предсказанием ветвлений или чем-то еще.

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

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

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

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

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

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

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

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

Ответы [ 7 ]

21 голосов
/ 06 июля 2010

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

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

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

1 голос
/ 06 июля 2010

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

1 голос
/ 06 июля 2010

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

{"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» и т. Д.

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

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

1 голос
/ 06 июля 2010

Может показаться, что Chrome обрабатывает строку integer , как если бы она была числовым типом при использовании в качестве имени индекса / свойства.

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

{
    "7":{"sortOrder":1,"data":["9149","9139","10455","17208"]},
    "7.5":{"sortOrder":2,"data":["9140","9150","10456","17209"]}
    //etc
}
0 голосов
/ 11 декабря 2018

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

<?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>
0 голосов
/ 08 мая 2013

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

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

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

0 голосов
/ 06 июля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...