Гугл Хром:Ассоциативные массивы JavaScript, вычисляемые вне последовательности
-
22-07-2019 - |
Вопрос
Итак, на веб-странице у меня есть объект 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 для структуры данных при обращении к ней.