Так, якщо припустити, що ваша реалізація включає в себе функцію for
...,of
запроваджену в ECMAScript 2015 (випуск "Гармонія") ... що ці дні є досить безпечним.
Це працює так:
// REQUIRES ECMASCRIPT 2015+
var s, myStringArray = ["Hello", "World"];
for (s of myStringArray) {
// ... do something with s ...
}
Або ще краще, оскільки ECMAScript 2015 також надає блок-області змінних:
// REQUIRES ECMASCRIPT 2015+
const myStringArray = ["Hello", "World"];
for (const s of myStringArray) {
// ... do something with s ...
}
// s is no longer defined here
(Змінна s
є різною для кожної ітерації, але все ще може бути оголошена const
всередині корпусу циклу, доки вона не буде змінена там.)
Примітка про розріджені масиви: масив у JavaScript може насправді не зберігати стільки елементів, скільки повідомляється в ньому length
; це повідомлене число просто на один більший за найвищий індекс, у якому зберігається значення. Якщо масив містить менше елементів, ніж зазначено його довжиною, його вважають рідким . Наприклад, абсолютно законно мати масив з елементами лише в індексах 3, 12 і 247; length
такого масиву повідомляється як 248, хоча на самому ділі тільки зберігати 3 значення. Якщо ви спробуєте отримати доступ до елемента в будь-якому іншому індексі, з'явиться масив, який має undefined
там значення. Тож, коли ви хочете "провести цикл" масиву, у вас є питання, на яке потрібно відповісти: чи хочете ви перевести цикл на весь діапазон, вказаний його довжиною та процесомundefined
s для відсутніх елементів, або ви хочете лише обробити фактично наявні елементи? Для обох підходів є безліч застосувань; це просто залежить від того, для чого ви використовуєте масив.
Якщо ви повторюєте масив з for
.. of
, тіло циклу виконується length
разів, і змінна керування циклом встановлюється undefined
для будь-яких елементів, які насправді відсутні в масиві. Залежно від деталей вашого коду "зроби щось з", така поведінка може бути тим, що ти хочеш, але якщо ні, ти повинен використовувати інший підхід.
Звичайно, деякі розробники не мають іншого вибору , крім як використовувати інший підхід в будь-якому випадку, тому що з якоїсь - то причини вони орієнтації версію JavaScript , який ще не підтримується for
... of
.
Поки ваша реалізація JavaScript відповідає попередній редакції специфікації ECMAScript (яка виключає, наприклад, версії Internet Explorer до 9), ви можете використовувати Array#forEach
метод ітератора замість циклу. У цьому випадку ви передаєте функцію, яку потрібно викликати для кожного елемента масиву:
var myStringArray = [ "Hello", "World" ];
myStringArray.forEach( function(s) {
// ... do something with s ...
} );
На відміну від for
... of
, .forEach
функція викликає лише ті елементи, які фактично є в масиві. Якщо ми передамо наш гіпотетичний масив з трьома елементами і довжиною 248, він викличе функцію лише три рази, а не 248 разів. Він також розрізняє відсутні елементи та елементи, які фактично встановлені undefined
; для останнього він все одно буде викликати функцію, передаючи undefined
в якості аргументу. Якщо це, як ви хочете обробляти розріджені масиви, .forEach
може бути шлях , навіть якщо інтерпретатор підтримує for
... of
.
Остаточний варіант, який працює у всіх версіях JavaScript, - це явний цикл підрахунку . Ви просто рахуєте від 0 до одного менше довжини і використовуєте лічильник як індекс. Основний цикл виглядає так:
var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
s = myStringArray[i];
// ... do something with s ...
}
Однією з переваг такого підходу є те, що ви можете вибрати, як обробляти рідкісні масиви; Наведений вище код буде працювати тіло циклу повні length
раз, з s
набором для undefined
будь-яких елементів, яких бракує, так само як for
.. of
. Якщо ви хочете обробити лише фактично наявні елементи розрідженого масиву, наприклад .forEach
, ви можете додати простий in
тест на індекс:
var i, s, myStringArray = [ "Hello", "World" ], len = myStringArray.length;
for (i=0; i<len; ++i) {
if (i in myStringArray) {
s = myStringArray[i];
// ... do something with s ...
}
}
Присвоєння значення довжини локальній змінній (на відміну від включення повного myStringArray.length
вираження в стан циклу) може суттєво змінити продуктивність, оскільки вона щоразу пропускає пошук властивості; використовуючи Rhino на моїй машині, швидкість становить 43%.
Ви можете побачити кешування довжини, виконане в пункті ініціалізації циклу, як це:
var i, len, myStringArray = [ "Hello", "World" ];
for (len = myStringArray.length, i=0; i<len; ++i) {
Явний цикл підрахунку також означає, що ви маєте доступ до індексу кожного значення, якщо ви цього хочете. Індекс також передається як додатковий параметр функції, до якої ви передаєте forEach
, тож ви також можете отримати доступ до нього таким чином:
myStringArray.forEach( function(s, i) {
// ... do something with s and i ...
});
for
... of
не дає вам індексу, пов’язаного з кожним об'єктом, але поки об'єкт, над яким ви повторюєтесь, насправді є Array
( for
.. of
працює для інших ітерабельних типів, які можуть не мати цього методу), ви можете використовувати масив метод #entries, щоб змінити його в масив [індекс, елемент] пар, а потім повторити це:
for (const [i, s] of myStringArray.entries()) {
// ... do something with s and i ...
}
for
... in
синтаксис вже зазначалося іншими для циклу за властивостями об'єкта; оскільки масив у JavaScript - це лише об'єкт із числовими іменами властивостей (та властивість, що автоматично оновлюється length
), ви можете теоретично перебирати на нього масив. Але проблема полягає в тому, що він не обмежує себе числовими значеннями властивостей (пам’ятайте, що навіть методи насправді є лише властивостями, значенням яких є закриття), а також не гарантується повторення даних у числовому порядку. Тому for
...in
синтаксис не повинен використовуватися для циклічного перегляду через масиви.