WEB制作
JavaScript | 10章:JavaScriptの反復処理を学ぼう
INDEX
目次

10章:JavaScriptの反復処理を学ぼう

本章では、JavaScriptの制御構文である反復処理を学びます。

「8章 JavaScriptの条件分岐を学ぼう」で解説したとおり、プログラムの処理パターンは、順次、分岐、反復の3つから成り立ちます。

反復は分岐と並んで大変重要なプログラムの処理方法ですので、しっかりと身につけましょう。


【10-1】反復(ループ)とは

  • 反復とは、特定の処理を繰り返し実行する処理のことで、ループ処理とも呼ばれます。

  • 例えば、5つ並んだテキストフォームの空欄チェックを順番に行う際、空欄チェックするための同じプログラムを5回書くよりも、1行で同じプログラムを5回繰り返す「ループ」の構文を使えば、ずっと短いコードで済みます。

  • 優秀なプログラマーであるほど、複雑で長いコードを整理して、より短いコードで記述する工夫ができます。そうすることで、入力から出力までにかかる時間を短縮させ、スムースに動くプログラムの処理を実現するのです。反復処理はそのような効率の良いプログラムを書くために役立ちます。

  • JavaScriptで反復処理を実行するための制御構文には、for文、while文、do…while文、for…in文、for…of文など複数の種類があります。

  • 本章では、その中でも代表的な反復処理の制御構文であるfor文の解説を主にしていきます。

  •  (10767)

    まずはシンプルなサンプルコードを記述して、for文のしくみを理解していきましょう。


    ■ for文 - 指定した回数だけループ処理をおこなう

    • 指定した回数だけ繰り返し処理を行うための構文が、for文です。
    • 書式は以下の通りです。

    一般的な書式だけでは、JavaScriptのループ処理を十分に理解するのは難しいかもしれません。
    そこで、より具体的な処理内容について、以下でコードを交えて解説していきます。

     (19081)


    ■ 処理を10回繰り返すfor文を書いてみよう

    上記のfor文の書式を使い、ある処理を10回繰り返し実行するプログラムを記述すると、このようになります。

    for (let i = 0; i < 10; i++) {
      //ここに10回繰り返す処理内容を書く;
    }
    サンプルコード10-1

    💡サンプルコード10-1の解説

    初期化式の役割
    • for文は冒頭の( )内に記述する初期化式、条件式、増減式の3つの式でループを制御します。

    • まず{ }内のコードが処理される最初のループ時に、初期化式が1回のみ実行されます。その後のループ中には実行されません。

    • 上記サンプルコード10-1では、「let i = 0;」が初期化式です。

    • この初期化式では、変数iを宣言し、初期値として0を代入しています。

    • for文の初期化式で宣言して使う変数のことをカウンター変数(ループ変数)、またはループカウンターといいます。これは、for文によるループの回数を管理するための変数のことです。

    • iという変数名は、カウンター変数の名前として慣習的によく使われるもので、添字を表すindexの頭文字をとったものだと言われています。


    条件式の役割
    • 続く条件式は、{ }内のコードがループ処理され続けるための条件を指定するものです。

    • if文の条件式と同様に比較演算子を使って式をつくります。

    • 上記サンプルコード10-1では、「i<10;」が条件式です。これは、3つめの式である増減式によって変動するカウンター変数iの中身が10未満である間だけ、ループ処理され続けるという意味です。


    増減式の役割
    • 3つめの式が増減式です。増減式は、{ }内の処理が1回実行される度に実行されます。
    • 通常は、 インクリメント(++)/ デクリメント(--)演算子 (「7章 変数と定数を学ぼう」の「よく使う算術演算子一覧」を参照)で、カウンター変数に1ずつ加算/減算する式を指定することが多いです。
    • 上記サンプルコード10-1では、増減式が「 i++」と記述されていますので、 ループが1回実行される度にカウンター変数iに1が加算されます。
      • カウンター変数iの初期値は0ですから、1回目のループ処理が実行される時点でのiの値は0です。処理が終わった後にiに1が加算されます。
      • 2回目のループでiの中身は1になり、3回目のループでiの中身は2になり、4回目のループで…と、条件式で指定された「 i<10;」という条件を満たしている間はこの処理が繰り返されます。
      • iが9のときに最後のループ処理が実行され、その後iが10になった時点で条件式(i < 10)が満たされなくなり、ループが終了します。
    • 初期化式の0の代入を含むと、 変数iに値が代入される処理が合計10回行われます。

     (10786)


    ■ for文で0から9までの数字をHTML中に書き出してみよう

    JS10-1演習データ.zip (1.01 KB)

    演習素材について
    • ダウンロードした「JS10-1演習データ」フォルダの中には、「for_start.html」と「for_fin.html」が入っています。
    • 「for_start.html」は作業用のファイルです。
    • 「for_fin.html」は完成データです。
    • 自分で書いたコードがうまく動作しないときは、完成データとの違いを探してみると良いでしょう。

    for_start.htmlを開いて下さい。


    上記の10回繰り返すfor文を使い、0から9までの数値をHTML中に順番に出力するサンプルファイルをつくってみましょう。

     (19082)

    <body>
      <h1>0から9までの数字をHTML中に書き出す</h1>
      <p class="number"></p>
    
      <script></script>
    </body>
    for_start.html サンプルコード10-2

    💡サンプルコード10-3の解説

    • for文のループ処理により、初期値として設定した0からスタートして1ずつ加算しながら、その数値をpタグの中に連続して出力するという処理を、合計10回繰り返すことが目的のサンプルコードです。

    • pタグにはnumberというclass名がついていますので、querySelectorで取得して定数pTagに代入し、オブジェクトを作成しておきます。

    • ループのfor文は、サンプルコード10-1をそのまま使います。同じ処理を10回繰り返す設定がしてあります。

    • 10回ループされる処理内容が、「 pTag.textContent += i ;」です。

    <body>
      <h1>0から9までの数字をHTML中に書き出す</h1>
      <p class="number"></p>
    
      <script>
        const pTag = document.querySelector(".number");
        for (let i = 0; i < 10; i++) {
          pTag.textContent += i;
        }
      </script>
    </body>
    for_start.html サンプルコード10-3

    代入演算子「=」と「+=」の違い
       

      代入演算子「=」を使った場合

         
      p要素オブジェクトのtextContentプロパティに変数iをセットするとき、代入演算子「=」を使ってしまうと、ループの度に出力した前回の処理結果が上書きされますので、10回目のループ処理の結果である9のみが出力されてしまいます。
    「pTag.textContent = i ;」と記述した場合のループ処理結果
     (19083)


      代入演算子「+=」を使った場合

        
      そこで、「左辺の値に右辺の値を加算したものを左辺に代入する」という意味の代入演算子「 +=」(7章参照) を使うことにより、前の処理結果の末尾に次の処理結果が追加されていきます。
    「pTag.textContent += i ;」と記述した場合のループ処理結果
     (19084)

    以上がfor文の基本です。


    【10-2】演習 for文でフォームの空欄チェックをループさせよう

    基本が理解できたところで、次に、もう少し実践的なサンプルを作成してみましょう。

    以下のサンプルデータをダウンロードして下さい。

    JS10-2演習データ.zip (2.45 KB)

    演習素材について
    • ダウンロードした「JS10-2演習データ」フォルダの中には、「if_check.html」「for_check_start.html」と「for_check_fin.html」が入っています。
    • 「if_check.html」は解説用のサンプルファイルです。
    • 「for_check_start.html」は作業用のファイルです。
    • 「for_check_fin.html」は完成データです。
    • 自分で書いたコードがうまく動作しないときは、完成データとの違いを探してみると良いでしょう。
  • この演習で作成するのは、すべての空欄を埋めないと送信できないというフォームの入力チェックです。
  • 8章 JavaScriptの条件分岐を学ぼう」をしっかり学んだ方でしたら、このしくみをif文を使って作ることはそれほど難しくはないはずです。

  • ■ for文のループ処理を使わずに記述した例

    まずはif_check.htmlをエディターで開き、ブラウザで動作確認をしてみましょう。


  • 8章で学んだif文を使うと、サンプルコード10-4で上記サンプルのしくみを実現することができます。

  • サンプルコード10-4では、for文のループは使用せずに、else if文を繰り返し記述することにより、4つのテキストフォームの空欄チェックを順番に行なっています。

  • もちろんこのコードでも、目的の挙動を実現することはできるのですが、似たような記述が繰り返され、やや冗長なプログラムであることは否めません。

  • そこで、同じ処理をfor文のループ処理を使うことにより、簡潔にまとめてみたいと思います。

  • <body>
      <h1>for文でフォームの空欄チェックをループさせる</h1>
      <h2>好きな食べ物を4つ教えて下さい!</h2>
      <form class="food-form">
        <p><input type="text" class="food-name1" /></p>
        <p><input type="text" class="food-name2" /></p>
        <p><input type="text" class="food-name3" /></p>
        <p><input type="text" class="food-name4" /></p>
        <p><input type="submit" value="送信する" /></p>
      </form>
    
      <script>
        //オブジェクト一覧
        const formObj = document.querySelector(".food-form");
        const foodNameElem1 = document.querySelector(".food-name1");
        const foodNameElem2 = document.querySelector(".food-name2");
        const foodNameElem3 = document.querySelector(".food-name3");
        const foodNameElem4 = document.querySelector(".food-name4");
    
        //送信イベントの設定
        formObj.addEventListener("submit", function (e) {
          //各テキストフォームに入力された文字列を取得して変数に格納する
          const foodName1 = foodNameElem1.value;
          const foodName2 = foodNameElem2.value;
          const foodName3 = foodNameElem3.value;
          const foodName4 = foodNameElem4.value;
    
          //if文で分岐処理、各テキストフォームが空欄かどうかを順番にチェックする。
          //空欄だった場合は、アラートでメッセージの表示とイベントキャンセル
          if (foodName1 == "") {
            alert("空欄をすべて埋めて下さい!");
            e.preventDefault();
          } else if (foodName2 == "") {
            alert("空欄をすべて埋めて下さい!");
            e.preventDefault();
          } else if (foodName3 == "") {
            alert("空欄をすべて埋めて下さい!");
            e.preventDefault();
          } else if (foodName4 == "") {
            alert("空欄をすべて埋めて下さい!");
            e.preventDefault();
          }
        })
      </script>
    </body>
    if_check.html サンプルコード10-4

    ■ for文のループ処理を使って記述した例

    for_check_start.htmlをエディターで開き、解説を読みながら自分でコードを入力して下さい。


    💡サンプルコード10-5の解説

    • まずはHTMLのマークアップ(サンプルコード10-5)を確認しましょう。

    • 今回、inputタグにはclass名をつけていません。

      • その理由は、DOMの要素オブジェクトではなく、ブラウザオブジェクトであるelementsオブジェクトを使うことによって、同じ処理の実現を目指すためです。
    <body>
      <h1>for文でフォームの空欄チェックをループさせる</h1>
      <h2>好きな食べ物を4つ教えて下さい!</h2>
      <form class="food-form">
        <p><input type="text" /></p>
        <p><input type="text" /></p>
        <p><input type="text" /></p>
        <p><input type="text" /></p>
        <p><input type="submit" value="送信する" /></p>
      </form>
    
      <script></script>
    </body>
    for_check_start.html サンプルコード10-5

  • 完成したJavaScriptのコードは次のようになります。

  • <script>
      //formタグの要素オブジェクトを作成する
       const formObj = document.querySelector(".food-form");
                //submitイベントを設定する
           formObj.addEventListener("submit", function (e) {
            //ループ処理
             for (let i = 0; i < formObj.length - 1; i++) 
              //テキストフォームの入力内容を取得して定数に代入する
               const foodName = formObj.elements[i].value;
               //空欄チェック
               if (foodName == "") {
                 alert("空欄をすべて埋めて下さい!");
                 e.preventDefault();//送信イベントキャンセル
                 return;//関数の処理を終了する
               }
             }
           })
    </script>
    JavaScript 完成コード サンプルコード10-6
  • だいぶ簡潔で短くなりましたね。このコードの挙動は、サンプルコード10-4の挙動と同じです。

  • それでは、コードの解説をしていきます。


  • 💡サンプルコード10-6の解説


      ✔️ 1. formタグの要素オブジェクトを作成する(サンプルコード10-7)

      • submitイベントを設定するために、あらかじめformタグの要素オブジェクトを作成しておきます。(サンプルコード10-7)
      //formタグの要素オブジェクトを作成する
      const formObj = document.querySelector(".food-form");
      サンプルコード10-7
      • formタグにはclass名をつけてありますので、今回はquerySelectorメソッドを使って要素オブジェクトを作成しましたが、ブラウザオブジェクトのformsオブジェクトを使い、以下のように記述しても問題ありません。(「5章 フォームオブジェクトを操作しよう」参照)

      const formObj = document.forms[0];
      サンプルコード10-8

      ✔️ 2. submitイベントを設定する(サンプルコード10-9)

      • この部分も、とくに問題なく理解できることと思います。

      • 送信時の空欄チェックでは、空欄だった場合にアラートでメッセージを出すだけではなく、データの送信をキャンセルする必要があります。(「9章 CONTACTフォームの入力チェックをやってみよう」参照)

      • eventオブジェクトのpreventDefaultメソッドを使ってsubmitイベントをキャンセルすると、データの送信が中止されることは9章で学習済みです。

      • eventオブジェクトの情報を受け取るために、あらかじめ関数の( )内に引数名eを記述しておきます。

      //formタグの要素オブジェクトを作成する
      const formObj = document.querySelector(".food-form");
      //submitイベントを設定する
      formObj.addEventListener("submit", function (e) {
      //ここにループ処理を記述する
      });
      サンプルコード10-9

      ✔️ 3. ループ処理(サンプルコード10-10)

      続いてfor文のループ処理です。

      初期化式

      • 変数iを宣言し、初期値0を代入します。

      条件式

      • テキストフォームは4つありますので、ループ回数は4回です。
      • 増減式で変数iに1ずつ加算しますから、「i<4」と記述すれば目的は達成できます。
      • しかしながら、このテキストフォームの数を、Webページの更新時に増やしたり減らしたりする可能性があった場合はどうでしょう。
      • その度にループの回数を修正しなければなりません。例えば、テキストフォームの数を3つに減らした場合、本章で学んだfor文の知識があれば、「i<4」を「i<3」に書き換えればよいことはすぐにわかりますが、HTMLとCSSの知識しかない人であれば、自力でJavaScriptを修正することは困難なのではないでしょうか。
      • HTMLの側でテキストフォームの数が増減しても、JavaScriptの側でその数を調べてくれるしくみをつくることができれば、修正不要な誰もが扱いやすいコードになり、プログラムの完成度が増します。
      • そのための条件式が「i<formObj.length - 1;」です。
      • formタグの要素オブジェクトのプロパティであるlengthプロパティは、フォームパーツの数を調べるためのプロパティで、<form></form>に含まれるinputタグなどのフォームパーツの数を取得します。
      • では、最後の「−1」はなぜ必要なのでしょうか?
      • HTML中の<input type="submit" value="送信する" /> は送信ボタンであり、このパーツだけは調べた数の中に含めたくないからです。送信ボタンの分を引いておかないと、4回ループさせたいときに5回ループしてしまうため、調べた数から1を減算しているのです。

      増減式

      • もっとも条件式を書きやすい定番のi++で、ループ回数の設定と紐づけします。
      //formタグの要素オブジェクトを作成する
      const formObj = document.querySelector(".food-form");
      //submitイベントを設定する
      formObj.addEventListener("submit", function (e) {
        //ループ処理
        for (let i = 0; i < formObj.length - 1; i++) {}
      });
      サンプルコード10-10

      ✔️ 4. テキストフォームの入力内容を取得して定数に代入する(サンプルコード10-11)

      • ここからは、ループ処理される内容の記述に入ります。

      • 今回作成するしくみのポイントは、ループする度に変数iに代入されていく値0、1、2、3と、elementsオブジェクトの添字(インデックス番号)0、1、2、3を連動させることです。

      • 「5章 フォームオブジェクトを操作しよう」で学んだように、<form></form>に含まれるinputタグなどのフォームパーツのことをelementsオブジェクトと呼びます。
        elementsオブジェクトはHTML中に記述されている順番で、添字(インデックス番号)が割り当てられており、elements[0]、elements[1]、elements[2]、elements[3]・・・という名前でブラウザに管理されています。

      • この番号部分を変数iに置き換え、elements[i]とすれば、最初のfor文のループでelements[0]が参照され、次のループでelements[1]が参照され、その次のループでelements[2]が参照され・・・・となります。

      • したがって、「const foodName = formObj.elements[i].value;」で、すべてのテキストフォームの入力内容をループの度に上から順番に取得し、foodName定数に代入するというプログラムの流れをつくることができるのです。

      //formタグの要素オブジェクトを作成する
      const formObj = document.querySelector(".food-form");
      //submitイベントを設定する
      formObj.addEventListener("submit", function (e) {
        //ループ処理
        for (let i = 0; i < formObj.length - 1; i++) {
          //テキストフォームの入力内容を取得して定数に代入する
          const foodName = formObj.elements[i].value;
        }
      });
      サンプルコード10-11

      ✔️ 空欄チェック(サンプルコード10-12)

      • 最後に空欄チェックです。

      • if文の条件式をfoodName == ""と記述し、取得したテキストフォームの入力内容が空欄かどうかのチェックを行います。

      • 空欄だった場合の処理内容は次のとおりです。

      空欄だった場合の処理内容

        1. アラートで「空欄をすべて埋めて下さい!」とメッセージを出力する

        2. イベントキャンセル(送信中止)

        3. 関数の処理を終了する(return文)

      1.と2.は学習済みですので解説は省略しますが、サンプルコード10-12内で、3.の処理に使われているreturn文についてはここで解説が必要となります。

      //formタグの要素オブジェクトを作成する
      const formObj = document.querySelector(".food-form");
      //submitイベントを設定する
      formObj.addEventListener("submit", function (e) {
        //ループ処理
        for (let i = 0; i < formObj.length - 1; i++) {
          //テキストフォームの入力内容を取得して定数に代入する
          const foodName = formObj.elements[i].value;
          //空欄チェック
          if (foodName == "") {
            alert("空欄をすべて埋めて下さい!");
            e.preventDefault(); //イベントキャンセル(送信中止)
            return; //関数の処理を終了する
          }
        }
      });
      サンプルコード10-12

      ■ return文とは

      まずは、サンプルコード10-12のreturnという記述がなかった場合のブラウザの挙動を確認してみましょう。

      //formタグの要素オブジェクトを作成する
      const formObj = document.querySelector(".food-form");
      //submitイベントを設定する
      formObj.addEventListener("submit", function (e) {
        //ループ処理
        for (let i = 0; i < formObj.length - 1; i++) {
          //テキストフォームの入力内容を取得して定数に代入する
          const foodName = formObj.elements[i].value;
          //空欄チェック
          if (foodName == "") {
            alert("空欄をすべて埋めて下さい!");
            e.preventDefault(); //イベントキャンセル(送信中止)
            //return文なし
          }
        }
      });
      空欄チェック(return文がなかった場合) サンプルコード10-13

      ⚠️ return文の必要性

      • 先ほどの動画で確認したように、何が問題か、わかりましたでしょうか?

      • 空欄が残っていた場合、アラートは表示されますし、データの送信も中止されます。

      • しかし、ループ処理自体はテキストフォームの数と同じ回数しっかりと実行されてしまうのです。

      • preventDefaultメソッドによって中止できるのは、データの送信というsubmitイベント発生時のHTMLの挙動だけであり、JavaScriptの処理であるfor文のループまでは中止できないということになります。

      • そのため、if文によって空欄が確認された際には、最初の空欄発見時に、ループを含めたイベント処理全体をストップする処理が必要となります。

      • そこで有用なのがreturn文です。

      • return文には以下のような機能があります。


      ✔️ return文の機能

        1. 関数の実行を終了する

        2. 関数に戻り値を設定する


    • 今回作成している空欄チェックのサンプルでは、1.の機能を利用しています。

    • 2.については、解説のためにもう1章割いてもよいくらい多くの使い方があるので、本章では割愛します。

    • 1.を簡潔に説明すると、関数内でreturnが実行されると、その時点で関数の処理が終了するということです。

      • return以降に別の処理が書かれていたとしても、その処理は実行されません。

      //formタグの要素オブジェクトを作成する
      const formObj = document.querySelector(".food-form");
      //submitイベントを設定する
      formObj.addEventListener("submit", function (e) {
        //ループ処理
        for (let i = 0; i < formObj.length - 1; i++) {
          //テキストフォームの入力内容を取得して定数に代入する
          const foodName = formObj.elements[i].value;
          //空欄チェック
          if (foodName == "") {
            alert("空欄をすべて埋めて下さい!");
            e.preventDefault(); //イベントキャンセル(送信中止)
            return; //関数の処理を終了する
          }
        }
      });
      空欄チェック(return文を記述した場合) サンプルコード10-14

      💡 完成したコード全体

      <body>
        <h1>for文でフォームの空欄チェックをループさせる</h1>
        <h2>好きな食べ物を4つ教えて下さい!</h2>
        <form class="food-form">
          <p><input type="text" /></p>
          <p><input type="text" /></p>
          <p><input type="text" /></p>
          <p><input type="text" /></p>
          <p><input type="submit" value="送信する" /></p>
        </form>
        
        <script>
          //formタグの要素オブジェクトを作成する
          const formObj = document.querySelector(".food-form");
          //submitイベントを設定する
          formObj.addEventListener("submit", function (e) {
            //ループ処理
            for (let i = 0; i < formObj.length - 1; i++) {
              //テキストフォームの入力内容を取得して定数に代入する
              const foodName = formObj.elements[i].value;
              //空欄チェック
              if (foodName == "") {
                alert("空欄をすべて埋めて下さい!");
                e.preventDefault(); //イベントキャンセル(送信中止)
                return;//関数の処理を終了する
              }
            }
          });
        </script>
      </body>
      サンプルコード10-15

      これで「10章:JavaScriptの反復処理を学ぼう」の解説を終わります。

      次の章に進みましょう。

      WEBCOACH | キャリアチェンジまでの全てを学ぶマンツーマンWEBスクール
      © 2020 by WEBCOACH