JavaScriptで学ぶ
文系の人にもわかるプログラミング入門

第6章   forループ

前の章で繰り返しのために使うwhileループを学びましたが, この章では別の種類の繰り返しであるforループについて説明します。

もうひとつのループ ── forループ

だいぶ計算練習らしくなってきましたが, 今度はいつまでも繰り返すのではなく, たとえば利用者に何問やるか問題数を聞いてその数だけやるようにしてみましょう。 whileループを使ってもできますが, 今度は「forループ」を使います。 それから, これを機会に, 足し算引き算をする部分を別の関数として外に出す(下請けに出す)ことにしましょう。

プログラム6-1 example06-01.html 計算練習5

12行目のprompt()で, 問題をいくつ解くか聞いています。 第2引数の「20」は「デフォルト値(default value)」で, あらかじめ表示しておく値を指定するためのものです。 図6-1のように入力欄にデフォルト値20が表示され, 単に[OK]を押せばこの値が戻るようになります。

図6-1 prompt()へのデフォルト値の指定

13-17行がfor文(forループ)です。

  13    for (i=1; i<= mondaiSu; i++) {
  14      if (tashizanHikizan() == null) {
  15        break;
  16      }
  17    }

forループは一般に次のような形式をもちます。

    for (<初期設定>; <再実行の条件>; <再設定>) {
        <処理部>
    }

whileの場合は, 次のループを実行するかどうかの判定(再実行の条件の判定)だけでしたが, forの場合は「初期設定」と「再設定」も加わります。 上のプログラムでは次のようになっています。

最後の「i++;」は「i = i+1;」と同じで, 今までのiの値に1を足したものが再度iに入りるので, 結果としてiが1だけ増えます。

メモ

「i++」と同様, 「i--」は「i = i-1」と同じ意味になります。 また, 「++i」「--i」のように++や--を前に書くことも可能です。 前に書く場合と後ろに書く場合で, 少し違いがありますが, 上の例のように独立した文として使うようにすれば, 同じ意味だと考えておいて大丈夫です。 たとえば次の例のように, if文の条件などで使うときは「++i」と「i++」との違いに注意しなければなりません。 ただ, こういった手法はとくに最初のうちは避けておく方がよいでしょう。

if (i++ > 3) {...}   // この文と下の文では, {...}が実行される場合が違う
if (++i > 3) {...}  

この2つの文を実行する前に, iが3だとすると, 下の場合だけ{...}の部分が実行されます。 それは++iの場合, iが3より大きいかを判定する前にiの値が1増加するためです。 3だったiの値は, 判定時には4になっているのです。 これに対して, i++とすると, iが3と比較されたあとでiの値が1増やされます。

上のfor文では, iが1, 2, 3, 4, 5, ...とループを回るたびに増えていって, mondaiSuと同じになったところが最後のループで, その次の回はiがmondaiSuの値を超えてしまうので, ループを抜けます。

  13      for (i=1; i<= mondaiSu; i++) {
                ...
  17      }

mondaiSuに20が入っていた場合は, iが20になるところまでループを回り, 21になったら<実行部分>を処理しないでforループを抜けるので, 合計で20回処理部を実行する(20回ループする)ことになるのです。

メモ

このforループの変数iのように, ループの回数や終了を判定するために使う変数のことを「ループ変数(loop variable)」と呼ぶことがあります。

forループの中身は14-16行目です。

  14         if (tashizanHikizan() == null) {
  15             break;
  16         }

tashizanHikizan()から返ってくる結果を見て, それがnullだった場合だけはbreakでループを強制的に抜けてしまいますが, ほかの場合はループを継続します。

20行目からのtashizanHikizan()はだいたいこれまでの処理と同じで, 問題を出して解答を受け取り正解を判定する, という作業を行っていますが, その後で答えが正しかったか, まちがったか, あるいは[キャンセル]が押されたかによって, 次のような値を返しています。

次の部分を見ましょう。

  39      kekka = 1; // 正解
  40      while (kotae != null && kotae != seikai) {
  41        kekka = 0;  // 不正解
  42        kotae = prompt("ざんねんでした。 もういちど:" + mondai, "")
  43      }
  44      if ( kotae == null ) {
  45        return null;
  46      }
  47      else {
  48        return kekka;
  49      }

まず39行目でkekkaの値を1にしています。 正解の時はこのまま48行目でkekka(つまり1)が戻されます。 もし, 最初に間違った場合は41行目でkekkaが0になり, この値が48行目で返されます。 「キャンセル」された場合はkotaeがnullになり, 45行目でnullが返ることになります。

tashizanHikizan()から返ってきた結果がnullの場合は, そこでforループを抜けて終わりになります。 このようにして, 途中でやめたくなった場合, やめられるようにしておきましょう。 「もう疲れたからやめたい」と思ってもやめられないのは拷問です。

これで, 1から10までの数字を使った足し算, 引き算を, 指定した回数だけ繰り返し練習するプログラムが完成しました。

forループとwhileループの比較

じつは, forループはwhileループを使って書くこともできて, 次のようにすると上のforループと同じ意味をもつwhileループになります。

    <初期設定>
    while (<再実行の条件>) {
        <処理部>
        <再設定>
    }

この手法で, 上の例の13-17行目のforループを書き換えてみましょう。

  13    for (i=1; i<= mondaiSu; i++) {
  14      if (tashizanHikizan() == null) {
  15        break;
  16      }
  17    }

    ↓

    i=1;
    while (i<= mondaiSu) {
      if (tashizanHikizan() == null) {
        break;
      }
      i++;
    }

逆にforループで, whileループを置き換えることもできます。 forループの(...)内に書く3つの要素の内, <初期設定>と<再設定>の部分は省略できるので,

    for ( ; <実行の条件>; ) {
        <処理部>
    }

と書けば

    while (<実行の条件>) {
        <処理部>
    }

と同じことになります。

forループとwhileループを比べてみると, forループではループに関係する操作をforに続く部分(...)にまとめて書くことができます。 このため, 「初期設定」「再設定」を必要とするループの場合は, forループを使ったほうが見通しがよくなります。 ループを制御するものを他の処理と分けて記述できるのです。 <初期設定>も<再設定>も必要がない場合でもforループを使ってループを書くことができ, 現にwhileループはまったく使わない人もいます。 ただ, whileを使うと, いかにも「条件が満たされる限り繰り返し」の感じが出るので, <初期設定>あるいは<再設定>の必要がない場合には, これを使う人もいます。

条件の追加 ── 繰り下がりのない引き算

小学生になって初めての夏休みが終わり2学期になると, 19までの数字を使った足し算, 引き算を練習します。 ただし, 「15-8」のように「繰り下がり」がある引き算は難しいので, まず第2項が10より小さくて繰り下がりのない引き算だけを勉強します。 今度は, この時期のドリル用のプログラムを作ってみましょう。 もう一度もまとめると, 次のような条件を満たす計算を出題する必要があります。

  1. 使う数字は, 足し算, 引き算とも19以下
  2. 足し算の合計は19以下
  3. 引き算の答えはマイナスになってはいけない
  4. 繰り下がりのある引き算は出してはいけない
  5. 引き算の第2項は9以下

(1)-(3)については上で対策を立てましたが, (4)はどのように処理すればよいでしょうか? 「繰り下がりがないようにする」ということは, 引き算の第1項(変数no1で表すほう)の1の位が, 第2項(変数no2で表すほう)の1の位より小さくてはいけない(大きいか同じでなければいけない)ということになります。

以上を考慮して作ったプログラムが次のものです。

プログラム6-2 example06-02.html 計算練習6

まず, 関数keisan()はこの前のものとまったく同じ。 繰り返しの方法などはまったく変わらないので, こちらは触る必要はありません。

直す必要があるのは, tashizanHikizan()のほうです。 肝(きも)となるのは引き算で繰り下がりがないようにする次のところです。

34         if (no1 > 10) {
35           no2 = randomInt(no1-10);
36         }
37         else {
38           no2 = randomInt(no1);
39         }

第1項(no1)が10より大きいときは, no1の1の位と同じかあるいはそれより小さい値を“ 引くようにします。 no1の1の位はno1の値から10を引くと計算できます(19以下の数字しか扱っていないので)。 そこで, no1-10をrandomInt()に渡します。 no1が10以下のときはそれと同じあるいはそれ以下の数を引くことができるので, no1をそのままrandomInt()に渡します。 混乱してしまった人は, もう一度上のソース(プログラム)を追って, 実行してみてください。

成績を出す ── カウンタの利用

この章のまとめとして, 指定した数だけ問題をやって, 最後に成績を知らせるようにしてみましょう。 今度は, 関数keisan()のほうを少し変えます。 また, ついでに問題を表示するときに, 何問目かも表示することにしてみましょう。

プログラム6-3 example06-03.html 計算練習7

先頭のほうの変数の宣言に次の3つが加わっています。

  11     var seikaiNoKazu = 0; // 正解
  12     var machigaiNoKazu = 0; // 間違い
  13     var kekka; // 正解か間違いか。 1なら正解, 0なら間違い, nullならキャンセル

最初の2つの変数に正解の数と間違いの数を覚えていきます。 最初はどちらも0なので, 変数の初期値は0にします。

メモ

上のようにあえて 「= 0」を書かなくても, とくに指定しないと変数の値は0または「""」(空文字列)が入っているとして扱われることになっています。 しかし, 上のようにあえて初期値を書いておくことによって0になっていることを再確認できるのです。

また, プログラミング言語によっては, 初期値を指定しないで変数を使うとエラーになる場合もあります。 したがって, 初期値をいつも指定するようにするのは, 悪くない習慣でしょう。

3つめのkekkaには, 正解だったか間違いだったかを記録します。 また, 答えを書かずに「キャンセル」を押した場合は, nullが返ってきます。

変数seikaiNoKazuとmachigaiNoKazuが使われているのは, 21行目と24行目のif...elseの処理部分です。

  21       else if (kekka == 1) {
  22         seikaiNoKazu++;
  23       }
  24       else {
  25         machigaiNoKazu++;
  26       }

seikaiNoKazuは正解の時に1増やされ, machigaiNoKazuは間違いの時に1増やされています。 このように, 何かの回数を数える役目をする変数のことを「カウンタ(counter)」と呼ぶことがあります。

関数keisan()の最後で使っているconfirm()は, 利用者から答えを受け取る必要はなくて, ただメッセージを表示して確認を求めるときに使うものです(図3-5)。 この関数からは[OK]が押されると1が, [キャンセル]が押されると0が戻ってきますが, ここでは返ってくる値は使いませんい。 値を返す関数を呼び出しても, その値が不要なら無視してかまいません。 ここで, alert()を使ってもよいですが, 新しい関数を覚えていただくよう使ってみました(本当はalert()を使ったほうがよいでしょう)。

図6-2 confirm()を使って成績を表示

まとめ

繰り返しの処理をする別種のループforループが登場しました。 同時に, 計算練習に付加したいろいろな条件をプログラムに反映する例をいくつか紹介しました。 できあがったプログラムを, より使いやすく便利にできないか検討し, たえず改良する気持ちを忘れないようにしましょう。

プログラミング一般

JavaScriptの構文

JavaScriptの関数(メソッド)

JavaScriptで学ぶ
文系の人にもわかるプログラミング入門
第6章 次の章へ