Гугл Хром:Ассоциативные массивы JavaScript, вычисляемые вне последовательности

StackOverflow https://stackoverflow.com/questions/640745

Вопрос

Итак, на веб-странице у меня есть объект JavaScript, который я использую как ассоциативный массив.Это существует статически в блоке скрипта при загрузке страницы:

var salesWeeks = {
    "200911" : ["11 / 2009", "Fiscal 2009"],
    "200910" : ["10 / 2009", "Fiscal 2009"],
    "200909" : ["09 / 2009", "Fiscal 2009"],
    "200908" : ["08 / 2009", "Fiscal 2009"],
    "200907" : ["07 / 2009", "Fiscal 2009"],
    "200906" : ["06 / 2009", "Fiscal 2009"],
    "200905" : ["05 / 2009", "Fiscal 2009"],
    "200904" : ["04 / 2009", "Fiscal 2009"],
    "200903" : ["03 / 2009", "Fiscal 2009"],
    "200902" : ["02 / 2009", "Fiscal 2009"],
    "200901" : ["01 / 2009", "Fiscal 2009"],
    "200852" : ["52 / 2008", "Fiscal 2009"],
    "200851" : ["51 / 2008", "Fiscal 2009"]
};

Порядок пар ключ/значение выбран намеренно, поскольку я превращаю объект в поле выбора HTML, например:

<select id="ddl_sw" name="ddl_sw">
<option value="">== SELECT WEEK ==</option>
<option value="200911">11 / 2009 (Fiscal 2009)</option>
<option value="200910">10 / 2009 (Fiscal 2009)</option>
<option value="200909">09 / 2009 (Fiscal 2009)</option>
<option value="200908">08 / 2009 (Fiscal 2009)</option>
<option value="200907">07 / 2009 (Fiscal 2009)</option>
<option value="200906">06 / 2009 (Fiscal 2009)</option>
<option value="200905">05 / 2009 (Fiscal 2009)</option>
<option value="200904">04 / 2009 (Fiscal 2009)</option>
<option value="200903">03 / 2009 (Fiscal 2009)</option>
<option value="200902">02 / 2009 (Fiscal 2009)</option>
<option value="200901">01 / 2009 (Fiscal 2009)</option>
<option value="200852">52 / 2008 (Fiscal 2009)</option>
<option value="200851">51 / 2008 (Fiscal 2009)</option>
</select>

...с кодом, который выглядит следующим образом (вырезан из функции):

var arr = [];
arr.push(
    "<select id=\"ddl_sw\" name=\"ddl_sw\">" +
    "<option value=\"\">== SELECT WEEK ==</option>"
);

for(var key in salesWeeks)
{
    arr.push(
        "<option value=\"" + key + "\">" +
        salesWeeks[key][0] + " (" + salesWeeks[key][1] + ")" +
        "<\/option>"
    );
}

arr.push("<\/select>");

return arr.join("");

Все это отлично работает в IE, FireFox и Opera.

Однако в Chrome порядок выглядит странно:

<select id="ddl_sw" name="ddl_sw">
<option value="">== SELECT WEEK ==</option>
<option value="200852">52 / 2008 (Fiscal 2009)</option>
<option value="200908">08 / 2009 (Fiscal 2009)</option>
<option value="200906">06 / 2009 (Fiscal 2009)</option>
<option value="200902">02 / 2009 (Fiscal 2009)</option>
<option value="200907">07 / 2009 (Fiscal 2009)</option>
<option value="200904">04 / 2009 (Fiscal 2009)</option>
<option value="200909">09 / 2009 (Fiscal 2009)</option>
<option value="200903">03 / 2009 (Fiscal 2009)</option>
<option value="200905">05 / 2009 (Fiscal 2009)</option>
<option value="200901">01 / 2009 (Fiscal 2009)</option>
<option value="200910">10 / 2009 (Fiscal 2009)</option>
<option value="200911">11 / 2009 (Fiscal 2009)</option>
<option value="200851">51 / 2008 (Fiscal 2009)</option>
</select>

ПРИМЕЧАНИЕ:Этот порядок, хотя и странный, не меняется при последующих обновлениях.Всегда в таком порядке.

Итак, что же делает Chrome?Некоторая оптимизация обработки цикла?

Во-первых, неправильно ли я полагаться на порядок объявления пар ключ/значение? любой ассоциативный массив?

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

Любое понимание было бы потрясающим.Спасибо.

Это было полезно?

Решение

Думайте об ассоциативном массиве как о бумажном пакете, в который помещены все пары ключ-значение. Когда вы подносите руку к мешку, чтобы посмотреть на пары (например, с помощью цикла for ... in), порядок, с которым вы сталкиваетесь, для всех практических целей является случайным.

Если вы хотите увидеть их в определенном порядке, вам нужно извлечь ключи в массив и отсортировать их. Затем пройдитесь по массиву, используя ключи, с которыми вы столкнетесь, для индексации в ассоциативный массив.

Другие советы

Порядок, в котором элементы хранятся в ассоциативном массиве, не гарантируется. Вам придется отсортировать вывод явно.

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

Chrome также перечислит их по порядку, если все свойства объекта содержат примитивные значения. Джон Резиг (John Resig) дает более подробную информацию о поведении Chrome здесь (в разделе «для порядка петель»): http://ejohn.org/blog/javascript-in-chrome/

Как указывалось выше, поведение Chrome совершенно корректно.

Это хороший случай, когда может помочь какое-то ОО-мышление. Вы действительно хотите ассоциативный массив или просто список объектов?

var salesWeeks = [
    ["200911", "11 / 2009", "Fiscal 2009"],
    ...
]
...
for(var key in salesWeeks)
{
    arr.push(
        "<option value=\"" + salesWeeks[key][0] + "\">" +
        salesWeeks[key][1] + " (" + salesWeeks[key][2] + ")" +
        "<\/option>"
    );
}
Я думаю, что

послужит вам лучше (для тех, кто выступает за какую-то форму, порядок уже определен - зачем вам делать дополнительную работу?)

@curtainDog: НЕТ! НЕТ! Использование «for .. in» с объектами Array в JavaScript - это плохо - суть большинства ответов здесь заключается в том, что «for .. in» не гарантирует какой-либо порядок. Более того, «for .. in» будет извлекать свойства из прототипа конструктора объекта и не будет перебирать несуществующие ключи.

@Samnan: спецификация просто говорит, что порядок итераций не гарантирован; это означает, что браузеры могут свободно выполнять итерацию в отсортированном порядке, в порядке вставки, в случайном порядке или, в противном случае, могут. Это похоже на хеш-таблицу - воспринимайте ее как случайную, даже если она выходит в некотором очевидном порядке.

Я уверен, что большинство браузеров ищут «for..in» с объектами Array и выполняют итерацию в числовом порядке, чтобы все не ломалось; однако, на самом деле он не делает то, что думает большинство людей, использующих его таким образом, и этого следует избегать, если вам специально не нужна итерация типа object .

Это не очень хорошая практика, но...

Если вы добавите пробел к значению, chrome не будет считать значение числом и не будет сортировать их по значению.

Пример:

<select>
  <option value=" 3">Third</option>
  <option value=" 1">First</option>
  <option value=" 2">Second</option>
</select>

Хорошая сторона заключается в том, что вам не нужно добавлять, а затем удалять буквенные символы из идентификатора, как предлагал кто-то (не помню, было ли в этом или другом сообщении с аналогичным вопросом), вы можете легко обрезать его, но в большинстве случаев пробел просто игнорируются, и если вы опубликуете или перенесете их в другой файл, они просто увидят целочисленное значение, а не пробел.

Вопреки всем другим ответам, это, безусловно, ошибка в цвете

Причина:

Если структура данных представляет собой бумажный мешок, как сказал Барри, то:

Значения всегда должны быть пересчитаны. Это не относится к Chrome

Если структура данных является последовательной, то:

Значения должны быть в той последовательности, в которой они добавлены в структуру

В то время как другие браузеры следуют второму подходу, Chrome не следует ни за одним, и до сих пор нет объяснения того, какой порядок сортировки компенсирует Chrome для структуры данных при обращении к ней.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top