Причина — в его поведении. Вот как работает обычный цикл ‘for’:
var a = []; a[5] = 5; // Полностью верный Javascript-код, который создаёт массив for (var i=0; i<a.length; i++) { // Перебирает все целочисленные индексы массива от 0 до 5, как и ожидается }
А теперь о том, как поведёт себя цикл ‘for in’ в этом случае:
var a = []; a[5] = 5; for (x in a) { // Цикл выполнится только один раз для 5 // и проигнорирует индексы 0-4 }
Также учтите, что библиотеки Javascript (типа MooTools) часто делают подобные вещи, которые будут иметь отношение ко всем массивам, которые Вы создаёте:
// Где-то глубоко в какой-нибудь Javascript-библиотеке: Array.prototype.foo = 1; // Попробуйте угадайте, что сделает следующий код: var a = [''a'',''b'',''c'',''d'',''e'']; for (var x in a){ // Сейчас ‘foo’ является частью ЛЮБОГО массива // и отобразится здесь как значение переменной ‘x’ console.log(x); // Выводит 0, 1, 2, 3, 4, foo (!!!) }
Для избежания этой проблемы можно поступить следующим образом:
for (var x in a) { // Отсеиваем здесь свойства не принадлежащие ‘a’ if (a.hasOwnProperty(x)) { console.log(x); // Получим 0, 1, 3, 3, 4 } }
Некоторые даже рекомендуют вызывать этот метод прямо из Object.prototype, чтобы избежать проблем в том случае, если кто-то добавит свойство с именем hasOwnProperty к Вашему объекту, хотя это и маловероятно.
for (var x in a) { if (Object.prototype.hasOwnProperty.call(a, x)) { console.log(x); // Получим 0, 1, 3, 3, 4 } }
Также поведение этого цикла может быть непредсказуемым в старых браузерах, таких как IE 8 и ниже:
var array = []; array[2] = ''c''; array[1] = ''b''; array[0] = ''a''; for (var p in array) { // В этом месте ‘p’ будет 2, 1 а затем 0 (в IE8 и ниже) }
При использовании цикла ‘for in’ всегда используйте ключевое слово var перед значением ключа, так Вы обезопасите себя от переназначения соответствующей переменной, если она встречается в глобальном контексте.
Вывод: использовать этот цикл можно, просто надо делать это с осторожностью.