Javascript для ... в выражении дает ошибку при циклическом прохождении массива - PullRequest
2 голосов
/ 06 сентября 2010

Я только что попробовал оператор for...in в Javascript.

Это не дает ошибки:

var images = document.getElementsByTagName('img');

for(x in images){
    document.write(images[x]) + " ");
}

Однако, это делает то, что должно, но выдает ошибку в консоли ошибок FF.

for(x in images){
    images[x].style.visibility="visible";
}

Это сделало меня ОЧЕНЬ любопытным, что происходит.

Делаем это:

for(x in images){
    document.write(x);
}

... дал мне это:

01234567891011121314151617lengthitemnamedItem

Что там в конце? Я предполагаю, что это делает массив document.images / document.getElementsByTagName('img') не подходящим для использования с оператором for...in, так как значения для x в конце не будут соответствовать изображению? Может быть, for петля лучше?

Ответы [ 3 ]

5 голосов
/ 06 сентября 2010

Не перебирайте массивы с циклами for ... in. Используйте индекс:

for (var i = 0; i < arr.length; ++i) {
  // images[i] ...
}

Конструкция for ... in не является неправильной , это просто не то, что вы хотите сделать; это когда вы хотите перебрать все свойства объекта. Массивы - это объекты, и помимо семантически интересных индексированных элементов есть и другие свойства.

(На самом деле то, что возвращается из getElementsByTagName, не является на самом деле массивом; это список узлов. Однако вы можете обращаться с ним как с массивом, и он, как правило, будет работать нормально. То же самое основное предупреждение применяется для for ... in в любом случае.)

1 голос
/ 06 сентября 2010

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

В любом случае, то, что вы получаете от document.getElementsByTagName , не является массивом . Это NodeList. Лучшая ставка для итерации по NodeList s - использовать явный индекс а-ля ответа Pointy - например, цикл прямого счета:

var i;
for (i = 0; i < list.length; ++i) {
    // ... do your thing ...
}

Несколько не по теме, потому что это не относится к вашему NodeList, но: когда вы на самом деле работаете с реальным массивом, поскольку массивы в JavaScript немногочисленны, для for..in есть применимость, вам просто нужно четко понимать, что вы делаете (просматривая имена свойств, а не индексы). Возможно, вы захотите выполнить цикл только столько раз, сколько массива содержит фактические записи, чем циклически проходить по всем индексам в промежутках в разреженном массиве. Вот как вы это делаете:

var a, name;
a = [];
a[0] = "zero";
a[10000] = "ten thousand";
for (name in a) {
    // Only process this property name if it's a property of the
    // instance itself (not its prototype), and if the name survives
    // transition to and from a string unchanged -- e.g., it's numeric
    if (a.hasOwnProperty(name) && parseInt(name) == name) {
        alert(a[name]);
    }
}

Выше приведены только два предупреждения: «ноль» и «десять тысяч»; в то время как цикл прямого счета без проверок будет предупреждать 10 001 раз (в основном, говоря «не определено», потому что он проходит через пробел).

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

Проблема с конструкцией for ... in заключается в том, что все из прототипа (ов) включается в перечисление.

То, что показывает ваш вывод, это в основном каждый атрибут из images, который является объектом массива. Итак, вы получите

  1. все элементы в вашем массиве, то есть числа, которые появляются в вашем выводе.
  2. все свойства, доступные в вашем массиве. Вот почему вы видите length в вашем выводе, например.

Ваш код ломается из-за номера 2, так как функции не имеют атрибута стиля

Итак, да, , как показывает Pointy , правильный способ перебора элементов массива в JavaScript - использование цикла for.

...