Что вызывает эту ошибку с for ... in после назначения Array.prototype.indexOf? - PullRequest
2 голосов
/ 23 апреля 2009

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

Ошибка заключается в том, что при выполнении for ... in в 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.

Ответы [ 2 ]

4 голосов
/ 23 апреля 2009

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

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

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

Больше информации в Центре разработчиков Mozilla :

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

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

4 голосов
/ 23 апреля 2009

См. " для интриги " на 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 предназначен для перебора ключей в объекте.

Steve

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...