Google Chrome: ассоциативные массивы JavaScript, вычисленные не по порядку - PullRequest
7 голосов
/ 13 марта 2009

Хорошо, поэтому на веб-странице у меня есть объект 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? Некоторая оптимизация в том, как он обрабатывает цикл?

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

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

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

Ответы [ 7 ]

10 голосов
/ 13 марта 2009

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

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

8 голосов
/ 13 марта 2009

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

2 голосов
/ 06 июля 2012

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

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

Пример:

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

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

2 голосов
/ 24 января 2011

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

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

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

2 голосов
/ 25 мая 2010

Как указывалось выше, поведение 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>"
    );
}

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

2 голосов
/ 13 марта 2009

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

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

0 голосов
/ 29 сентября 2010

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

Причина:

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

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

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

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

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

...