Должен ли Javascript for в конструкции повторять свойство длины?

Я делаю букмарклет, но столкнулся со странным поведением в IE8. Код, вызывающий проблему, таков:

var els = document.getElementById("my_id").getElementsByTagName("*");
for(var i in els)
{
    alert(i+","+els[i])
}

Первое, что настораживает, это длина, n. В хроме такого нет: только в IE8.

Интересно, что он ведет себя по-разному в зависимости от того, находится ли код в консоли/адресной строке или на самой странице.

Это стандартное поведение?

РЕДАКТИРОВАТЬ:

Не вплоть до веб-сайта, на котором я его запускаю. Возможно ли, что getElementsByTagName возвращает массив с ключом "length", установленным в IE? Он, конечно, не возвращает чистый массив.


person Eric    schedule 24.03.2010    source источник


Ответы (6)


То, что вы получаете, это не массив, это список узлов. См. здесь, щелкните ссылку "getElementsByTagName('element_name')"

Кроме того, for..in в любом случае не предназначен для перебора массива. Использовать

var item;
for (var idx=0, len=arr.length; idx<len; ++idx) {
  item = arr[idx];
  // whatever
}

для итерации массива.

Для нодлиста вы можете получить элемент с помощью

list.item(idx); // where list is what you got from getElementsByTagName

если вы хотите сделать это "правильно".

person npup    schedule 24.03.2010
comment
Я почти уверен, что вы хотите idx++ вместо ++idx. В противном случае вы пропустите первый элемент. - person Josh Stodola; 24.03.2010
comment
Нет, все в порядке. idx равен 0 до тех пор, пока не будет оценена последняя часть for-expression. Что такое ++idx. Вот порядок: 1: var idx=0, len=arr.length 2: idx<len 3: {код тела} 4: ++i Так что ++idx или idx++ по этой причине не имеет значения. - person npup; 24.03.2010
comment
Спасибо за разъяснения ;) Думаю, я просто настолько привык видеть i++, что это показалось мне чуждым! - person Josh Stodola; 24.03.2010
comment
На самом деле ++idx немного лучше, потому что он обновляет idx. idx++ клонирует idx. На практике это, вероятно, не имеет большого значения - person plodder; 30.03.2010

Поведение IE правильное. Он может возвращать всевозможные странные вещи, поскольку for .. in выполняет итерацию по всем именам членов объекта.

getElementsByTagName возвращает NodeList, а свойства NodeList указываются в стандарт DOM: length и item(i). Большинство реализаций JavaScript также позволяют [i].

Поэтому следует написать следующее:

var els = document.getElementById("my_id").getElementsByTagName("*");
for (var i = 0;i < els.length;i++)
{
    alert(i+","+els.item(i));
}
person phihag    schedule 24.03.2010

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

person Chetan S    schedule 24.03.2010

Вот как я перебираю списки. Таким образом, вам не придется писать в цикле лишнюю строку, например var el = els[i].

var els = document.getElementById("my_id").getElementsByTagName("*");
for (var i=0, el; el=els[i]; i++) {
    // do what you like here
}
person mojbro    schedule 24.03.2010

Нет, если вы не определите свой собственный итератор для NodeLists, который предназначен только для JavaScript (Mozilla). [Вот реализация] того, что я создал для своего репозитория js-iterators.

person Eli Grey    schedule 24.03.2010

Часто бывает полезен метод преобразования объекта, такого как список узлов, объект аргументов или пользовательский объект, в массив его элементов.

Array.from= function(what){
 var L, A= [];
 if(!what) what= {};
 L= what.length;
 if(typeof L== 'number'){
  while(L) A[--L]= what[L];
  return A;
 }
 for(var p in what){
  if(what.hasOwnProperty(p)) A[A.length]= what[p];
 }
 return A;
}

var N=Array.from(document.getElementById("my_id").getElementsByTagName("*"))
while(N.length){
tem=N.shift();
}
person kennebec    schedule 24.03.2010