【初心者向け】JavaScript入門⑤「配列(array)とグローバル変数」

#はじめに
[初めてのJavaScript(オライリー本)](https://www.amazon.co.jp/%E5%88%9D%E3%82%81%E3%81%A6%E3%81%AEJavaScript-%E3%82%B7%E3%82%A7%E3%83%AA%E3%83%BC-%E3%83%91%E3%83%AF%E3%83%BC%E3%82%BA/dp/4873113229)を調達しましたが、筆者にとって少しとっつきにくい。そこで、本書のサポートページにあるコラム[『JavaScriptで学ぶ文系の人にもわかるプログラミング入門』](https://www.marlin-arms.com/jpn/column/js101/lesson03.html)から出発することにしました。

# 学習すること
***[第7章 配列とグローバル変数(loop)](https://www.marlin-arms.com/jpn/column/js101/lesson07.html)***

>変数、演算子、関数、分岐(if...else)、繰り返し(whie...,for...)など、多くの概念が登場しましたが、まだとても重要なものがひとつ残っています。ごくまれな例外を除いて、ほとんどすべてのプログラミング言語に備わっているのが「配列(array)」です。この章では、この「配列」を使って、「計算練習」をさらに発展させていきましょう。

***目次***
* ①同じ問題は出したくないー配列に記憶
* ②グローバル変数（大域変数）とローカル変数（局所変数）
* ③たくさんの値をまとめて記憶するー配列
* ④まとめ

# ①同じ問題は出したくないー配列に記憶

>前の章の最後で、採点まで表示することになり、だいぶ計算ドリルらしくなりましたが、まだまだ改良の余地があります。まず気になるのが、1回のドリル（たとえば20問）の中で、同じ問題が出題されることです。前にまちがっていたので、もう1回同じのを出すのなら話は別ですが、簡単にできたのに同じのを出すのは止めたいところです。この問題を解決するには、それより前に出した問題を記憶しておく必要があります。そのために配列を使いましょう。


# プログラム7-1 example07-01.html 計算問題

```html:example07-01.html計算問題

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>けいさん８</title>
<!-- 配列を使って記憶して、同じ問題を出さない -->
<script type="text/javascript">
function keisan()　{
    var mondaiSu; // 問題数
    var i;
    var seikaiNoKazu = 0;   // 正解
    var machigaiNoKazu = 0; // 間違い
    
    mondaiSu = prompt("たしざん　ひきざん。" +
                      "なんかい　やりますか？",20);　// 問題数を入力させる
    for (i=1; i<= mondaiSu; i++) {　　　　　　　　　// 指定した分の問題数を表示する
        var kekka = tashizanHikizan(i);
        if (kekka == null) {　          // キャンセルボタンを押されたとき(戻り値=null)
            break;
        }
        else if (kekka == 1) {          // 正解したとき(戻り値=1)
            seikaiNoKazu++;
        }
        else {                          // 間違えたとき(戻り値=0)
            machigaiNoKazu++;
        }
    }
    alert("せいかいのかず　" + seikaiNoKazu + "　もん:" +    //ﾀﾞｲｱﾛｸﾞﾎﾞｯｸｽ(回答結果)を表示
          "まちがいのかず　" + machigaiNoKazu + "　もん");
}

function tashizanHikizan(i) {　// 足し算か引き算を１回実行
    var no1, no2; // 第１項、第２項
    var mondai, seikai, kotae;　// 問題,正解,答え
    var enzan;   // "+"か"-"
    var kekka;   // 正解(1)か不正解か(0)
    var saidaiKotae = 19;
    
    do {                                 // なぜdo...while文なのか？
        no1 = randomInt(saidaiKotae-1);  // 最大答え(-1)の乱数をno1(第１項)に代入
        if(randomInt(2) == 1) {  　　　　 // 足し算の場合
            enzan = " + ";
            no2 = randomInt(saidaiKotae-no1);
            seikai = no1 + no2;
        }
        else {                             // 引き算の場合
            enzan = " - ";               
            if (no1 > 10) {                // 第１項(no1)が１０より大きい場合
                no2 = randomInt(no1-10);   // 第１項(no1)から１０引いた数値までの乱数
            }
            else {                         // 第１項(no1)が１０以下の場合
                no2 = randomInt(no1);　　   // 第１項の乱数を第二項に代入
            }
            seikai = no1 -no2;　　　　　　   // 計算結果をseikaiに代入
        }
        mondai = no1 + enzan + no2 + " =";　// 問題を生成（第１項 +/- 第２項 =）
    }
    while (mondaiChofuku(mondai));          // すでに前に出された問題であれば、処理を繰り返す（別の問題を生成する）
    
    kotae = prompt("だい" + i + "もん: " + mondai, "");　// 正解をkotaeに代入？
    kekka = 1;  　　　　　　　　　　　　　　　　　　　　　　　// 初期値(=正解)をkekkaに代入
    while (kotae != null && kotae != seikai) {          // キャンセルでも、正解でもない
        kekka = 0;　　　　　　　　　　　　　　　　　　　　　　// つまり、不正解
        kotae = prompt("ざんねんでした。もういちど:" + mondai, "") // 問題を再表示
    }
    if ( kotae == null ) {　　　　 // キャンセルボタンを押されたとき
        return null;              // 戻り値=nullを返す
    }
    else {                        // 正解のとき
        return kekka;             // 戻り値=1を返す
    }
}

// 「大域変数（グローバル変数,global variable）」※以前出された問題を記憶し続ける
var MondaiKioku = new Array();　　 // 配列をMondaiKiokuに代入
var MondaiBangou = 0;             // MondaiBangouの初期化(MondaiBangou=0だとforﾙｰﾌﾟが初回で終わらないか?)
    
function mondaiChofuku(mondai) {
    for(var i=0; i<MondaiBangou; i++) {　// iがMondaiBangouより小さい間は繰り返す。「i(0) < mondaiBangou(0)」初回で終了?
        if (MondaiKioku[i] == mondai) {　// 過去に同じ問題が出力されていないか？
            return true;　　　　　　　　　　// 出題されてる？
        }
    }
    MondaiKioku[MondaiBangou] = mondai;　// 
    MondaiBangou++;
    return false;
}

function randomInt(i) {
    // 1以上i以下の整数を返す
    return( Math.floor(Math.random()*i) + 1 );
}
</script>
</head>
    
<body onload="keisan();">
<h1>けいさんれんしゅう</h1>
</body>
</html>
```

# ②グローバル変数（大域変数）とローカル変数（局所変数）

```html;example07-01.html

var MondaiKioku = new Array();
var MondaiBangou = 0;
```

>これまでの変数はすべてfunction xxxx {...}の...の範囲に入っていたのに、
この2行はどの関数にも属していません。このように変数を宣言すると、「大域変数（グローバル変数、global variable）」を宣言したことになります。今まで使ってきた変数は、関数の本体を表す{...}の...の部分に書かれており、この場合その関数内部でしかその変数にアクセスすること（その変数の値を見たり、その変数に値を代入したりすること）はできませんでした。関数内部でのみ有効な「局所変数（ローカル変数、local variable）」だったのです。

# ③たくさんの値をまとめて記憶するー配列

>出した問題を次々に記憶していかなければならないので、そのためにかなりの数の変数が必要になります。そのための機構が「配列」です。
>74行目は配列の宣言で、MondaiKiokuという配列を新たに作成しています。実際にこの配列を使っているのは78行目からのfor文の中です。

```html:example07-01.html計算問題(74-86行目)

var MondaiKioku = new Array();
var MondaiBangou = 0;  // これまでにいくつ問題を生成したか？

function mondaiChofuku(mondai) {
    for (var i=0; i<MondaiBangou; i++) {
       if (MondaiKioku[i] == mondai) {  //問題を比較
	  return true;　//生成した問題が過去のものと重複してる
       }
    }
      MondaiKioku[MondaiBangou] = mondai;
      MondaiBangou++;　 // 新たな問題を生成するたびに1プラス
      return false;　//生成された問題はすでに出された問題ではない、の意。
}
```

### for文の処理

>for分の最初でまず変数iを宣言して0に初期化し、iがMondaibangouよりも小さいかチェックされます。一番最初にこの関数が呼ばれたときは、MondaiBangouの値は0で、iも0なのでこの条件は成り立たず（真にならず）、forの<処理部>は一度も実行されずに下に行ってしまいます。つまり、まだ問題は1個も出してないので、前に出した問題と比較する必要はないというわけです。

### 問題（文字列）をMondaiKioku[MondaiBangou] (配列)に代入

>for文に続く次の行が実行されるとき、MondaiBangouは0になって、変数mondaiにこの上で生成した問題が文字列として入っています。

```html:example07-01.html計算問題(83行目)

MondaiKioku[MondaiBangou] = mondai;
//「MondaiKioku[0] = mondai;」が実行されるのと同じ
// 問題1はMondaiKioku[0]、問題2はMondaiKioku[1]、問題3はMondaikioku[2]に格納
```


# ④まとめ

***全体の動作***
* グローバル変数の配列を使って、それまでに出した問題を記憶しておく。
* 問題を生成時に、配列に記憶されている要素すべてとの比較により、すでに出した問題かどうかをチェックする。このときループ（for文）を使う。
* 同じ問題だった場合は、もう一度生成して同じようにチェックする。これをまったく新しい問題が生成されるまで繰り返す。

##プログラミング一般

* 配列（Array()）
* グローバル変数（大域変数）とローカル変数（局所変数）

## JavaScriptの構文

* do...while文ーー最低１回は処理部を実行するループ

```js
	 do {
	      <処理部>
	 } while (<再実行の条件>);`
```

# ⑤次回やること
[第８章　HTMLの表機能](https://www.marlin-arms.com/jpn/column/js101/lesson08.html)

>第7章までの「計算練習」では、ダイアログボックスを使って問題を1問ずつ表示しては答えを入力してもらって、ブラウザのウィンドウには簡単なメッセージを書いただけでした。それなりに計算の練習にはなるでしょうが、利用者の使い勝手（使いやすさ）を考えると大きな改良の余地がありそうです。

# おわり
今回はここまでです。