Почему JavaScript For... В цикле не рекомендуется для массивов?

Я где-то читал (извините, я не могу найти ссылку), что цикл For... In не рекомендуется для массивов. Здесь говорится: http://www.openjs.com/articles/for_loop.php, что он предназначен для ассоциативных массивов, а в http://www.w3schools.com/js/js_loop_for_in.asp, который предназначен для итерации по всем свойствам объекта (он не говорит, что его можно использовать на массивах). Я не знаю, кому верить. Я не хочу, чтобы этот вопрос стал дебатом. Я просто хочу знать, могу ли я использовать это в своем коде без непредвиденных побочных эффектов. Спасибо!

Ответы

Ответ 1

Массив - это объект, а элементы массива - это просто свойства с числовым индексом, преобразованным в строку. Например, arr [123] ссылается на свойство "123" в объекте массива arr.

Конструкция for ... in работает на всех объектах, а не только на массивах, и это вызывает недоумение.

Когда кто-то for ... in массива, чаще всего программист намеревается итерировать только все элементы, даже наиболее вероятно по порядку. Например, если массив содержит кучу чисел, то программист, скорее всего, намерен итерировать поток чисел. Семантика настолько похожа на итерацию массива на других языках программирования, что очень легко запутаться.

В JavaScript эта конструкция не упорядочивает элементы массива. Он выполняет итерацию всех имен свойств (включая имена унаследованных функций прототипа, любые добавленные к нему свойства, любые другие неэлементные свойства, добавленные к нему и т.д.), А не в порядке вообще. В более ранних браузерах он даже найдет свойство length, хотя в последних браузерах эти свойства теперь определены как скрытые по этой точной причине - люди продолжают спотыкаться об этом!

С массивом целых чисел, указанным выше, вы получаете не поток чисел, а поток текстовых строк. И не значения элементов, а имена свойств (которые являются только числовыми индексами не в любом порядке). Скорее всего, это не то, что означает программист, если он приходит с другого языка программирования. Если элементы, хранящиеся в массиве, похожи на числовые значения, это сбивает с ума всех.

Вот почему вы не должны этого делать. Вы не должны использовать конструкцию языка, которая выглядит так, как будто она имеет очевидные вещи, но на самом деле делает вещи совершенно разные. Это создает ошибки, которые очень неясны и очень трудно найти.

Ответ 2

Я протестировал итерацию массива в нескольких браузерах (FireFox 3, Opera 9, IE6, IE9 beta, Chrome), и он отлично работает; Кажется, я помню некоторую кросс-браузерную несовместимость, но я должен ошибаться.

Тем не менее, есть еще одна оговорка:

Как вы уже упоминали, синтаксис for ... in используется для итерации по свойствам объекта; поэтому с массивом все свойства этого объекта массива также будут повторяться вместе с элементами. Обычно объект массива имеет только свойства, соответствующие ключам в нем, но если другой script изменяет Array.prototype (например, некоторую структуру), то добавленные методы/атрибуты неожиданно появятся и на итерации.

Ответ 3

В документации документации Prototype.js приведено несколько веских причин: http://www.prototypejs.org/api/array

В принципе, использование для... in для итерации массива является хрупким, поскольку любой другой код может добавлять свойства к прототипу Array, который затем станет перечислимым свойством для каждого объекта массива.

Ответ 4

Итерация по массиву с помощью for(... in ...) не даст вам числовых ключей, он получит строковые значения.

Он предоставит вам свойства, определенные на прототипе, поэтому, если какой-либо код расширяет Array, например. делая:

Array.prototype.each = ...;

то вы увидите свойство each.

Нет gaurantee, что вы получите свойства в порядке индекса массива. Например. повторите попытку

var arr = []
arr[1] = 1;
arr[0] = 0;

Во многих браузерах вы получите 1 до 0.

И вам не гарантировано получить все индексы. Попробуйте выполнить повторение

[0,,,3]

вы не получите индекс 1 или 2.