この記事は技術レビューを必要としています。ぜひご協力ください。
この記事は編集レビューを必要としています。ぜひご協力ください。
ループは繰り返し何かを実行するための簡便な方法を提供します。本章では JavaScript で利用可能な反復処理を行う数々の文を紹介します。
誰かに話しかけようと、ある方向に X 歩進み、別の方向に Y 進むといった場面を、コンピュータ化されたゲームととらえた上で、ループについて考えてみましょう。例えば、「西に 5 歩進む」という概念はループとして、下記のように表現できます :
var step; for (step = 0; step < 5; step++) { // 値が 0 から 4 まで計 5 回実行される console.log('1 歩西に歩く'); }
様々な種類のループがありますが、それらはすべて基本的に同じことをします : ループは行動を数回繰り返します(そして、その回数をゼロとすることは実際可能です)。様々なループ機構は、ループの開始点と終了点を決定するためのさまざまな方法を提供しています。色々な状況によって、あるループよりも別のタイプのループがより簡単に目的を果たします。
JavaScript で提供されるループ文は以下のとおりです :
for
文
for
文によるループは指定された条件が false と評価されるまで繰り返されます。JavaScript の for ループは Java や C 言語の for
ループと同じです。for
文は以下のようになります :
for ([initialExpression]; [condition]; [incrementExpression]) statement
for
ループが実行されるとき、次の処理が行われます :
- もしあれば、初期化式
initialExpression
が実行されます。この式は通常、1 個またはそれ以上のループカウンタを初期化しますが、この構文ではいかなるレベルの複雑な式を入れることが可能です。初期化式で変数を宣言することもできます。 - 条件式
condition
が評価されます。condition
の値が true の場合、ループ文が実行されます。condition
の値が false の場合、for
ループは終了します。condition
式がすべて省略されている場合、条件式は真であると仮定されます。 - 文
statement
が実行されます。複数の文を実行するには、それらの文をグループ化するためにブロック文 ({ ... }
) を使用します。 - もしあれば、更新式
incrementExpression
が実行され、ステップ 2 に制御が戻ります。
次の関数にはスクロールリスト(複数選択できる <select>
要素)で選択したオプションの数をカウントする for
文があります。for
文が変数 i
を宣言しゼロに初期化します。i
が <select>
要素のオプション数未満であることがチェックされると、後続の if
文が実行され、オプションが選択されていれば、ループの各通過後に 1 個ずつ i
が加算されます。
<form name="selectForm"> <p> <label for="musicTypes">Choose some music types, then click the button below:</label> <select id="musicTypes" name="musicTypes" multiple="multiple"> <option selected="selected">R&B</option> <option>Jazz</option> <option>Blues</option> <option>New Age</option> <option>Classical</option> <option>Opera</option> </select> </p> <p><input id="btn" type="button" value="How many are selected?" /></p> </form> <script> function howMany(selectObject) { var numberSelected = 0; for (var i = 0; i < selectObject.options.length; i++) { if (selectObject.options[i].selected) { numberSelected++; } } return numberSelected; } var btn = document.getElementById("btn"); btn.addEventListener("click", function(){ alert('Number of options selected: ' + howMany(document.selectForm.musicTypes)) }); </script>
do...while
文
do...while
文は指定された条件が false になるまで繰り返します。do...while
文は以下のようになります :
do statement while (condition);
statement
の文は条件 condition
がチェックされる前に一度実行されます。複数の文を実行するには、それらの文のグループ化にブロック文 ({ ... }
) を使用します。条件が true の場合、文が再び実行されます。すべての実行終了時に条件がチェックされます。条件が false の場合、実行は停止し制御は do...while
に続く文に渡ります。
次の例では、do
ループは少なくとも一度繰り返されます。そして i
が 5 未満でなくなる直前まで繰り返しされます。
var i = 0; do { i += 1; console.log(i); } while (i < 5);
while
文
while
文は指定された条件が true に評価されると文を実行します。while
文は以下のようになります :
while (condition) statement
条件 condition
が false となる場合、ループ内の文 statement
は実行を停止し、ループに続く文に制御が渡されます。
ループ内の文が実行される前に条件がテストされます。条件が true を返す場合、statement
は実行され、条件が再びテストされます。条件が false を返す場合、実行は停止し、while
に続く文に制御が渡されます。
複数の文を実行するには、それらの文をグループ化するブロック文 ({ ... }) を使用します。
次の例では、while
ループは、n
が 3 未満の場合繰り返されます。:
n = 0; x = 0; while (n < 3) { n++; x += n; }
各反復で、ループは n
がインクリメントされ、その値が x
に加算されます。こうして、x
と n
は以下の値をとります:
- 1 回目の通過後 :
n
= 1,x
= 1 - 2 回目の通過後 :
n
= 2,x
= 3 - 3 回目の通過後 :
n
= 3,x
= 6
3 回目の通過完了後、条件式 n < 3
はもはや true ではなくなるため、ループが終了します。
無限ループ
無限ループは避けてください。ループ内の条件が最終的に false になることを確かめるようにしましょう。さもないと、ループは永遠に終了しません。次の while
ループ文は、条件が決して false にならないので永遠に実行されます :
while (true) { console.log("Hello, world"); }
label
文
label
を使って、プログラム内の他の場所から参照できる識別子を組み込んだ文が作成できます。例えば、ループの識別にラベルを使い、そのプログラムでループを中断するか、実行を継続するかどうかを指定する場合に、ラベルを break
文や continue
文で使用することができます。
ラベル文の構文は以下のようになります :
label : statement
label
の値には、予約語でなければあらゆる JavaScript 識別子を使用できます。ラベルによって識別される文 statement
はどんな文でもかまいません。
この例では、ラベル markLoop
は while
ループを指し示しています。
markLoop: while (theMark == true) { doSomething(); }
break
文
ループ、switch
、ラベル文を使った関連付けを終了させるには break
文を使います。
ラベルなしで break
を使用すると、最も内側の while
、do-while
、for
、switch
をただちに終了し、次の文に制御を移します。この場合の break
文の構文は下記のようになります。:
break;
次の例では、値が theValue
である要素のインデックスを探すまで配列の要素を反復します。:
for (i = 0; i < a.length; i++) { if (a[i] == theValue) { break; } }
ラベルとともに break
を使用すると、指定されたラベル文を終了します。この場合、break
文の構文は下記のようになります :
break label;
次の例では、二つの while ループが入れ子になっており、外側のループを抜けるのにラベルを使用しています。
var x = 0; var z = 0 labelCancelLoops: while (true) { console.log("Outer loops: " + x); x += 1; z = 1; while (true) { console.log("Inner loops: " + z); z += 1; if (z === 10 && x === 10) { break labelCancelLoops; } else if (z === 10) { break; } } }
continue
文
continue
文は while
、do-while
、for
、label
文を再開する際に使用されます。
ラベルなしで continue
を使用すると、その文を囲んでいる最も内側の while
、do-while
、for
文による現在の反復を終了し、次の反復のループの実行を継続します。break
文とは対照的に、continue
は完全にループの実行を終了しません。while
ループの場合、条件にジャンプします。for
ループでは、increment-expression
にジャンプします。
この場合の continue
文の構文は下記のようになります :
continue;
次の例では、i
の値が 3 のときに実行される continue
文が使用された while
ループを示しています。この場合、n
の値は 1、3、7、12 となります。
var i = 0; var n = 0; while (i < 5) { i++; if (i == 3) { continue; } n += i; }
ラベルとともに continue
を使用すると、この動作がそのラベルによって識別されるループ文に対して適用されます。この場合の continue
文の構文は下記のようになります :
continue label;
次の例では、checkiandj
とラベル付けされた文には checkj
とラベル付けされた文が含まれています。continue
文に出会うと、プログラムは checkj
の現在の反復を終了し次の反復を開始します。continue
に出会うたびに、checkj
はその条件が false
を返すまで繰り返されます。false
が返されると、checkiandj
の残りの部分が完了し、その条件がfalse
を返すまで checkiandj
が繰り返されます。false
が返されると、プログラムは checkiandj
に続く文を継続します。
もし continue
が checkiandj
のラベルを持っていると、プログラムは checkiandj
のラベル文の先頭から継続されます。
checkiandj: while (i < 4) { console.log(i); i += 1; checkj: while (j > 4) { console.log(j); j -= 1; if ((j % 2) == 0) { continue checkj; } console.log(j + " is odd."); } console.log("i = " + i); console.log("j = " + j); }
for...in
文
for...in
文はオブジェクトにあるすべての列挙可能なプロパティに対し指定された変数を通して反復処理を行います。それぞれの異なるプロパティに、JavaScript は指定された文を実行します。for...in
文は下記のようになります :
for (variable in object) { statements }
次の関数は引数としてオブジェクトと、そのオブジェクトの名前を表す文字列を取ります。それからすべてのオブジェクトのプロパティに対して反復し、プロパティ名とその値を表示する文字列を返します。
function dump_props(obj, obj_name) { var result = ""; for (var i in obj) { result += obj_name + "." + i + " = " + obj[i] + "<br>"; } result += "<hr>"; return result; }
make
プロパティと model
プロパティを持つ car
オブジェクトに対し、result
は下記のようになります :
car.make = Ford car.model = Mustang
配列
Array
要素に対して反復処理を行う方法として for...in 文を使用することができますが、これは数値のインデックスに加えてユーザ定義プロパティの名称も返します。そういうわけで、配列に対しての反復処理には、数値のインデックスを使い従来の for
ループを使用するほうが良いです。というのも、カスタムプロパティやカスタムメソッドを追加するといった Array オブジェクトの変更を行った場合、for...in 文は配列要素に加えてユーザ定義プロパティに対しても反復処理するからです。
for...of
文
これは Harmony(ECMAScript 6) 提案の一部であり、実験段階の技術です。
この技術の仕様は安定していません。ブラウザ互換性の一覧表を確認してください。またこれらの構文や動作は、仕様変更などにより、新しいバージョンのブラウザでは変更される可能性があるという点に注意してください。
for...of
文は、反復可能オブジェクト(Array
、Map
、Set
、arguments オブジェクトなどを含む)を反復処理するループを生成し、それぞれのプロパティの値に対して実行したい文をともなって作られた反復処理フックを呼び出します。
for (variable of object) { statement }
次の例では、for...of
ループと for...in
ループとの違いを示しています。for...in
はプロパティ名に対し反復処理される一方、for...of
はプロパティの値に対し反復処理します :
let arr = [3, 5, 7]; arr.foo = "hello"; for (let i in arr) { console.log(i); // logs "0", "1", "2", "foo" } for (let i of arr) { console.log(i); // logs "3", "5", "7" }