【Javascript基礎】制御構文

# 目次
**◆ - if命令 -（条件によって処理を分岐する）**

**◆ - switch命令 -（式の値によって処理を分岐する）**

**◆ - while/do...while命令 -（条件式によってループを制御する）**

**◆ - for命令 -（指定回数だけループ処理をする）**

**◆ - break/continue命令 -（ループを途中でスキップ/中断する）**

**◆ - Strictモード -（危険な構文を禁止する）**


# ◆ - if命令 -（条件によって処理を分岐する）
if命令は、「もし〜だったら...、　さもなくば...」という構造を表現するためのもの。
与えられた条件式が **true/false** いずれであるかによって、対応する命令（群）を実行する。

```javascript
if(条件式) {
  条件式がtrueの場合に実行する命令
} else {
  条件式がfalseの場合に実行する命令
}
```

**例）**

```javascript
let num = 10;

if(num >= 5) {
 console.log('変数xは５以上である。');
} else {
 console.log('変数xは５未満である');
}
/**
 * 変数xが5以上　→ 変数xは5以上である
 * 変数xが5未満　→ 変数xは５未満である
 */
```
このように、if命令では指定された条件式がtrue（真）なら**その直後のブロック**を、
false（偽）の場合は**else以降のブロック**をそれぞれ実行する。

※ブロック → {}で囲まれた部分のこと。

また、elseは省略が可能。
上記の変数が5以上の時のみ処理を実行したい時には省略すれば良い。
```javascript
if(num >= 5) {
 console.log('変数xは５以上である。');
}
```

## ・ else ifブロックによる多岐分岐
else ifを利用することで、複数の分岐を表現することが可能。
```javascript
if(条件式1) {
  条件式1がtrueの場合に実行する命令
} else if(条件式2) {
  条件式2がtrueの場合に実行する命令
}
・・・
} else {
  全ての条件式がfalseの場合に実行する命令
}
```
else ifブロックは、必要になる分岐の数だけ列記できる。
```javascript
let x = 30;

if(x >= 20) {
  console.log('変数xは20以上です。');
} else if(x >= 10) {
  console.log('変数xは10以上です。');
} else {
  console.log('変数xは10未満です。');
}

// 結果：変数xは20以上です。
```
この時、変数xは条件式「x >= 10」の方にも合致しているのに、表示しているメッセージは「変数xは20以上です。」だけが表示される。

理由は、if命令は複数の条件に合致する場合、実行されるブロックは最初の1つだけであるから。今回の場合は「x >= 20」の方に合致するため、2番目以降のブロックが実行されることはない。

従って、以下のようなスクリプトは意図したような動作をしない。
else ifを利用する際は、**<font color="red">条件式を記述する順番に注意すること。</font>**
```javascript
let x = 30;

if(x >= 10) {
  console.log('変数xは10以上です。');
} else if(x >= 20) {
  console.log('変数xは20以上です。');
} else {
  console.log('変数xは10未満です。');
}

// 結果：変数xは10以上です。
```

# ◆ - switch命令 -（式の値によって処理を分岐する）
if命令だけでシンプルな分岐から複雑な分岐まで柔軟に表現することはできるが、
以下のような条件分岐を作成したい場合は、if命令よりも、**switch命令**を利用することが好ましい。
**■if文**
```javascript
let rank = 'B';

if(rank === 'A') {
  console.log('ランクはAです。');

} else if(rank === 'B') {
  console.log('ランクはBです。');

} else if(rank === 'C') {
  console.log('ランクはCです。');

} else {
  console.log('ランク外です。');
}

// 同じような記述も多く、冗長に見える。
```
**■switch文**
```javascript
switch(式) {
  case 値1 :
    「式 = 値1」である場合に実行される命令（群）
  case 値2 :
    「式 = 値2」である場合に実行される命令（群）
  ・・・
  default :
    全ての値が全ての式に合致しない場合に実行される命令（群）
}
```
```javascript
let rank = 'B';

switch(rank) {
  case 'A' :
    console.log('ランクはAです。');
    break;

  case 'B' :
    console.log('ランクはBです。');
    break;

  case 'C' :
    console.log('ランクはCです。');
    break;

  default :
    console.log('ランク外です。');
    break;
}

// 結果　ランクはBです。
```
ここで注目すべき点は、「case/default」句の末尾に必ず、**<font color="red">break命令</font>** を指定しているという点。
**<font color="red">break命令</font>** とは、現在のブロックから処理を脱出するための命令。

**<font color="red">switch命令では、条件に合致するcase句に移動するだけで、その句を終えても自動的にswitchブロックを終了するわけではない。</font>**

break命令を取り除いた状態で先ほどの処理を実行すると、以下のようになる。
```javascript
let rank = 'B';

switch(rank) {
  case 'A' :
    console.log('ランクはAです。');

  case 'B' :
    console.log('ランクはBです。');

  case 'C' :
    console.log('ランクはCです。');

  default :
    console.log('ランク外です。');
}

/**
 * ランクはBです。
 * ランクはCです。
 * ランク外です。
 */
```
## ・ 意図したbreak命令の省略
break命令は、処理したい内容次第では省略した方が良いケースもある。
以下のその例。
```javascript
let score = 70;

switch(score) {
  case 70 :
  case 80 :
  case 90 :
  case 100 :
    console.log('合格です。');
    break;

  default :
    console.log('不合格です。');
    break;
}

// 結果　合格です。
```

## ・ switch式とcase値は「＝＝＝」で比較
switch命令の先頭の式と、case句の値は、**「===」演算子**で比較される点に注意。
**例）　以下の処理は実行されない。**
```javascript
let x = '0';

switch(x) {
  case 0 :
    console.log('xは0です。');
}

// 結果　何も表示されない。
```
「===」演算子では、'0'と0では異なるものであるため、実行されない。
ブラウザからの入力値を元に処理するような状況では、上記のような文字列と数値の比較がよく発生する。

# ◆ - while/do...while命令 -（条件式によってループを制御する）
こちらは条件分岐ではなく、繰り返し処理。

**while命令**
```javascript
while(条件式) {
  条件がtrueである時に実行される命令（群）
}

// 具体例

let x = 8;

while(x < 10) {
  console.log('xの値は' + x);
  x++;
}

/**
 * 結果
 * xの値は8
 * xの値は9
 */
```
**do...while命令**
```javascript
do {
  条件がtrueである時に実行される命令（群）
} while(条件式);

// 具体例

let x = 8;

do {
  console.log('xの値は' + x);
  x++;
} while(x < 10);

/**
 * 結果
 * xの値は8
 * xの値は9
 */
```
一見どちらも同じように見えるが、変数を以下のように変更すると違いが解りやすい。
```javascript
let x = 10;

while(x < 10) {
  console.log('xの値は' + x);
  x++;
}
// 結果　出力なし


do {
  console.log('xの値は' + x);
  x++;
} while(x < 10);

// 結果　xの値は１０
```
while命令では何も出力されないが、
do...while命令では「xの値は10」が1回出力される。

これは、while命令はループの最初で条件式を判定する（**<font color="blue">前置判定</font>**）であり、do...while命令はループの最後で条件式を判定する（**<font color="blue">後置判定</font>**）であるから。

:::note info
**前置判定 → 条件次第では一回もループ処理されない。**

**後置判定 → 条件の真偽に関わらず、1回は必ずループ処理される。**
:::

# ◆ - for命令 -（指定回数だけループ処理をする）
指定された回数だけループ処理を行うのがfor命令。
```javascript
for(初期化式; ループ継続条件式; 増減式) {
  ループ内で実行する命令（群）;
}
```
```javascript
for(let i = 8; i < 10; i++) {
  console.log('xの値は' + x);
}
```
**for命令のループ処理の順番**

①最初のループで。初期化式を1回実行する。（let i = 8）

②ループ継続条件式が「x < 10」 なので、xが１０未満の間、ループ処理を繰り返す。

③ブロック内の処理が実行される度、増減式が実行される。

## ・ カンマ演算子
カンマ演算子を利用することで、for命令の式を複数指定することができる。

**※複数指定できるのは、初期化式と増減式。**
```javascript
for(let i = 1, j = 1; i < 5; i++, j++) {
  console.log(i * j);
}

/**
 * 結果
 * １
 * ４
 * ９
 * １６
 */
```

## ・ - for...in命令 -（連想配列の要素を順に処理する）
for...in命令では、指定された連想配列（オブジェクト）の要素を取り出して、先頭から順に処理する。
```javascript
for(仮変数 in 連想配列) {
  ループ内で実行する命令（群）
}
```
**仮変数**とは、連想配列のキーを一時的に格納するための変数。
仮変数には要素値そのものは代入されない点に注意。
```javascript
let books = { magazine: 200, comic: 220, newspaper: 50 };

for(key in books) {
  console.log(key + '=' + books[data]);
}
/**
 * magazine=200
 * comic=220
 * newspaper=50
 */
```
## ・ for...in命令の注意点
for...in命令を使用する上では、以下の点に注意する必要がある。

**①拡張した機能まで列挙してしまう。**

**②配列では使用しない方が良い。**

**①の例**
```javascript
let array = [10,20,30];

array.prototype.func = function() {};

for(key in array) {
  console.log(array[key]);
}

/**
 * 結果
 * 10, 20, 30, function(){}
 */
```
配列で使用しない方がいい理由としては、

**・処理される順序がfor...in命令では保証されない。**

**・仮変数にはインデックス番号が格納されるだけで、あまりシンプルな書き方にならない。**

という理由が挙げられる。

## ・ - for...of命令 -（配列などを順に処理する）
配列などを順番に列挙するためのもう一つの手段が、for...of命令。
「配列など」というのは、配列だけでなく、Arrayライクなオブジェクト（NodeList、argumentsなど）、イテレーター/ジェネレーターなども処理できるため。
これらを総じて、**列挙可能なオブジェクト**とも呼ぶ。
```javascript
for(仮変数 of 列挙可能なオブジェクト) {
  ループ内で実行する命令（群）
}
```
```javascript
let obj = {'magazine', 'comic', 'newspaper'};

for(value of obj) {
  console.log(value);
}

/**
 * 結果
 * magezine, comic, newspaper
 */
```

一見for...in命令と同じように見えるが、for...of命令では、仮変数に列**挙している値**が入っている点が違う。

# ◆ - break/continue命令 -（ループを途中でスキップ/中断する）
for命令等の繰り返し処理を行う際、**「特定の条件を満たした場合、ループを強制的に中断/スキップしたい」** というときに使用する命令。

**break（処理の中断）の例**
```javascript
let result = 0;

for(let i = 0; i <= 100; i++) {
  result += i;
  if(result > 1000) {
    console.log('合計値が1000を超えるのは' + i);
    break;
  }
}

// 合計値が1000を超えるのは45
```
iが100以上になる前に、処理が終了しているのが分かる。

**continue（処理のスキップ）の例**
```javascript
let result = 0;

for(let i = 0; i < 10; i++) {
  if(i % 2 == 0) {
    continue;
  }
  result += i;
}
console.log(result);

// 25
```
iが偶数の時に処理をスキップし、奇数だけを合計しているのが分かる。

## ・ ネストされたループは最も内側を脱却する。
繰り返し処理の中に繰り返し処理があるような状態のことを**ネスト**という。
このネストされたループの中でbreak/continue命令を使用した場合は、デフォルトでは、最も内側のループを脱却するようになっている。
```javascript
for(int i = 1; i < 10; i++) {
  for(int j = 1; j < 10; j++) {

    let result = i * j;
    
    if(result > 30) {
      break;
    }
    document.write(result + '&nbsp');
  }
  document.write('<br/>');
}

/**
 * 結果
 * 1 2 3 4 5 6 7 8 9
 * 2 4 6 8 10 12 14 16 18
 * 3 6 9 12 15 18 21 24 27
 * 4 8 12 16 20 24 28
 * 5 10 15 20 25 30
 * 6 12 18 24 30
 * 7 14 21 28
 * 8 16 24
 * 9 18 27
 */
```
ネストされたfor命令で、iとjをかけた数字が30を超えた時、break命令が出される。
この時繰り返し処理は終了せず、一番内側のfor命令の処理から脱却し、外のfor命令の処理に戻っている。

## ・ - ラベル構文 -（任意の場所に処理を飛ばす）
ラベル構文を利用することで、脱却先を任意の場所に指定することができる。
```javascript
// 飛ばしたい場所に記載
ラベル名:

// 発動してほしい場所に記載
break ラベル名:
```
**例）**
**「３０を超えたら、処理を停止してほしい」**
```javascript
stop : // 30を超えたらここに処理が飛ぶ

for(int i = 1; i < 10; i++) {
  for(int j = 1; j < 10; j++) {

    let result = i * j;
    
    if(result > 30) {
      break stop;
    }
    document.write(result + '&nbsp');
  }
  document.write('<br/>');
}
```

## ・ - try...catch...finally命令 -（例外を処理する）
**「数値を受け取ることを想定した関数に文字列が渡された」、**
**「変数を参照しようとしたら未定義であった」**
などの、開発時には想定しなかった様々なエラー **（例外）** が発生することがある。

そのようなエラーが発生した際、スクリプト（プログラムのこと）全体が停止してしまわないようにするのが例外処理の役割。
```javascript
try {
  例外が発生するかもしれない命令（群）

} catch(例外情報を受け取る変数) {
  例外が発生した時に実行される命令（群）

}finally {
  例外の有無に関わらず、最終的に実行される命令（群）
}
```
**例）**
```javascript
let x = 1;

try {
    i = i * j;
}catch(e) {
    console.log(e.message);
}finally {
    console.log('処理完了');
}
console.log('処理継続');
/**
 * j is not defined
 * 処理完了
 * 処理継続
 */

/*----------------------------*/

let x = 1;

 i = i * j;

console.log('処理継続');

/**
 * Main.js:11
 * i = i * j;
 * ^
 */

// ReferenceError: i is not defined .....
// 処理継続のコンソール出力は発動せず
```
try...catch...finally命令をすることで、例外が起きてもその後の処理が継続されており、
逆にしていないと、例外が起きる箇所で処理がストップしてしまい、後続の処理が発動しないことが分かる。

## ・ - throw命令 -（明示的に例外を発動させる）
例外は意図的に発動させることもでき、その際は**throw命令**を使用する。
```javascript
let x = 1;

let y = 0;

try {
  if(y === 0) {
    throw new Error('0で徐算しようとしました。');
  }catch(e) {
    console.log(e.message);
  }
}
/**
 * 結果
 * 0で徐算しようとしました。
 */
```
例外を発生させるのが　throw命令の役割。
例外を発生させることを、 **「例外をスロー（throw）する」** ともいう。

例外の原因に応じて、様々なErrorオブジェクトがある。
| オブジェクト | エラーの原因 |
|:-:|:-:|
| EvalError  | 不正なeval関数  |
| RangeError  | 指定された値が許容範囲を超えている  |
| ReferenceError  | 宣言されていない変数にアクセスした  |
| SyntaxError  | 文法エラー  |
| TypeError  | 指定された値に期待されたデータ型がない  |
| URIError  | 不正なURI  |

# ◆ - Strictモード -（危険な構文を禁止する）
Javascriptには、
**「仕様としては存在するが、現在では安全性や効率面で利用すべきではない構文」** 
というものが存在する。

このような落とし穴を開発者が避けて開発するのは、開発者に大きな負担となる。また、開発者のレベルによっては完全に防ぐことは不可能。

そこで、Javascriptがその落とし穴を検出し、エラーとして通知してくれるものが **<font color="red">Strictモード</font>** である。

**■Strictモードの有効**
```javascript
// ①スクリプトの先頭
'use strict'


/*------------------------*/
// 関数の本体先頭
function hoge() {
 'use strict'
}
```
**■Strictモードの通知対象**

**・ var命令の省略の禁止**

**・ 引数・プロパティ名の重複の禁止**

**・ with命令の使用の禁止**

などがある。

# 参考文献

https://gihyo.jp/book/2016/978-4-7741-8411-1