ループと反復処理

この記事は技術レビューを必要としています。ぜひご協力ください

この記事は編集レビューを必要としています。ぜひご協力ください

ループは繰り返し何かを実行するための簡便な方法を提供します。本章では 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 ループが実行されるとき、次の処理が行われます :

  1. もしあれば、初期化式 initialExpression が実行されます。この式は通常、1 個またはそれ以上のループカウンタを初期化しますが、この構文ではいかなるレベルの複雑な式を入れることが可能です。初期化式で変数を宣言することもできます。
  2. 条件式 condition が評価されます。condition の値が true の場合、ループ文が実行されます。condition の値が false の場合、for ループは終了します。condition 式がすべて省略されている場合、条件式は真であると仮定されます。
  3. statement が実行されます。複数の文を実行するには、それらの文をグループ化するためにブロック文 ({ ... }) を使用します。
  4. もしあれば、更新式 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 に加算されます。こうして、xn は以下の値をとります:

  • 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 はどんな文でもかまいません。

この例では、ラベル markLoopwhile ループを指し示しています。

markLoop:
while (theMark == true) {
   doSomething();
}

break

ループ、switch、ラベル文を使った関連付けを終了させるには break 文を使います。

ラベルなしで break を使用すると、最も内側の whiledo-whileforswitch をただちに終了し、次の文に制御を移します。この場合の 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 文は whiledo-whileforlabel 文を再開する際に使用されます。

ラベルなしで continue を使用すると、その文を囲んでいる最も内側の whiledo-whilefor 文による現在の反復を終了し、次の反復のループの実行を継続します。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 に続く文を継続します。

もし continuecheckiandj のラベルを持っていると、プログラムは 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 文は、反復可能オブジェクトArrayMapSetarguments オブジェクトなどを含む)を反復処理するループを生成し、それぞれのプロパティの値に対して実行したい文をともなって作られた反復処理フックを呼び出します。

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"
}

ドキュメントのタグと貢献者

 このページの貢献者: tao-s, x2357, shide55
 最終更新者: tao-s,