2009-04-23 1 views
2

Я был удивлен, когда смог воспроизвести ошибку с минимальным количеством кода. Обратите внимание, что в этом минималистском примере Array.indexOf не вызывается. Также обратите внимание, что я пробовал несколько различных реализаций indexOf, включая несколько из stackoverflow.com.Что вызывает эту ошибку для for ... in после назначения Array.prototype.indexOf?

Ошибка при запуске в IE, отображаются три предупреждения: «indexOf», «0» и «1». В FF, как и следовало ожидать, появляются только два («0», «1»).

<html> 
<body onLoad="test();"> 
<script language="javascript"> 
    var testArray = ['Foo', 'Bar']; 

    if(!Array.prototype.indexOf) { 
     Array.prototype.indexOf = function (obj, fromIndex) { 
     if (fromIndex == null) { 
      fromIndex = 0; 
     } else if (fromIndex < 0) { 
      fromIndex = Math.max(0, this.length + fromIndex); 
     } 
     for (var i = fromIndex, j = this.length; i < j; i++) { 
      if (this[i] === obj) 
       return i; 
     } 
     return -1; 
     }; 
    } 

    function test() { 
     var i; 

     for(i in testArray) { 
     alert(i); 
     } 
    } 
</script> 
</body> 
</html> 

Может ли это объяснить это? Я уже изменил свой код, чтобы использовать while, поэтому я не под пистолетом, но на самом деле у меня все в тупике. Это напоминает мне ошибки переполнения памяти в c.

ответ

4

См. "for in Intrigue" на Yahoo! Блог пользовательского интерфейса.

Причина, по которой ваш код работает должным образом в Firefox, заключается в том, что вы не добавили свой собственный метод indexOf в Firefox. Цикл for in выполняет итерацию по всем ключам в цепочке прототипов объекта, включая добавленный вами метод indexOf. Дуглас Крокфорд предлагает следующее решение:

for (var p in testArray) { 
    if (testArray.hasOwnProperty(p)) { 
     alert(testArray[i]); 
    } 
} 

В качестве альтернативы, вы можете просто отфильтровать функции:

for (var p in testArray) { 
    if (typeof testArray[p] !== "function") { 
     alert(testArray[i]); 
    } 
} 

Кроме того, как «nickf» указывает, что лучше не использовать петлю for in для переборе над массивами. Цикл for in предназначен для итерации по клавишам в объекте.

Стив

+0

Благодарим вас; это именно то, что мне нужно. – overslacked

+0

Вы действительно не должны использовать for..in на массивах вообще. См. Ссылку в моем ответе. – nickf

+0

@Steve: Поскольку ничего не сломано, я бы не вызвал использование «hasOwnProperty()» исправления. ;-) – Tomalak

4

for .. in предназначен для зацикливания через свойства объекта, безусловно, не массивы.

Придерживайтесь стандартом:

for (var i = 0, l = myArray.length; i < l; ++i) { .. } 

Более подробная информация на Mozilla Developer Centre:

for...in цикла не перебирать встроенные свойства. К ним относятся все встроенные методы объектов, такие как метод indexOf String или метод toString объекта. Тем не менее, цикл будет перебирать все пользовательские свойства (в том числе любые, которые переписывают встроенные свойства).

Хотя может быть заманчиво использовать это как способ перебора массива, это плохая идея. Оператор for ... in выполняет итерации над определяемыми пользователем свойствами в дополнение к элементам массива, поэтому, если вы изменяете нецелые или неположительные свойства массива (например, добавляя к нему свойство «foo» или даже добавляя метод или свойство в Array.prototype), оператор for ... in вернет имя ваших пользовательских свойств в дополнение к числовым индексам.

+0

Как я упоминал в вопросе, это минималистский пример, который только воспроизводит проблему; но ваша точка хорошая. – overslacked

+0

Чтобы убедиться, что я даю правильные кредиты, ваш ответ был на 100% точным; но это была исходная информация, представленная в ответе Стива о том, почему проблема возникает вообще во что мне нужно. Спасибо за помощь! – overslacked

Смежные вопросы