Так, якщо припустити, що ваша реалізація включає в себе функцію 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там значення. Тож, коли ви хочете "провести цикл" масиву, у вас є питання, на яке потрібно відповісти: чи хочете ви перевести цикл на весь діапазон, вказаний його довжиною та процесомundefineds для відсутніх елементів, або ви хочете лише обробити фактично наявні елементи? Для обох підходів є безліч застосувань; це просто залежить від того, для чого ви використовуєте масив.
Якщо ви повторюєте масив з 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 синтаксис не повинен використовуватися для циклічного перегляду через масиви.