JavaScript文法(4) 制御構文と関数

# この記事の内容

* JavaScriptの制御構文（条件分岐、繰り返し）の書き方
* JavaScriptの関数の書き方

# 目次

(1) [学習環境の構築と基本的な書き方](http://qiita.com/azk0305/items/a13d494178d83fc8f2bc)
(2) [変数とデータ型](http://qiita.com/azk0305/items/d78d744dff9656b22dd0)
(3) [演算子および配列](http://qiita.com/azk0305/items/748f4afadcfa5350a552)
(4) 制御構文と関数 **<-- この記事の内容**
(5) [関数の応用1](http://qiita.com/azk0305/items/f7e0653b20425fdb9f1b)
(6) [関数の応用2](http://qiita.com/azk0305/items/0fd54f9c66f726443dd6)
(7) [オブジェクトの基礎](http://qiita.com/azk0305/items/0d2018a1c6e547b7f65a)
(8) [JavaScriptのオブジェクト指向プログラミング1 概要](http://qiita.com/azk0305/items/1e1bd10522927eaddd6a)
(9) [JavaScriptのオブジェクト指向プログラミング2 オブジェクトの作り方と継承](http://qiita.com/azk0305/items/386b3a2ac41caf3101e1)
(10) [JavaScriptのオブジェクト指向プログラミング3 多態性](http://qiita.com/azk0305/items/1c713562f6f842dcf1dc)
(11) [JavaScriptのオブジェクト指向プログラミング4 カプセル化](http://qiita.com/azk0305/items/914f6e447b41d4ced25e)
(12) [ES6の新機能について](http://qiita.com/azk0305/items/ebfb43c088101f7138f9)

# 条件分岐

## if文

この記事では、条件分岐と繰り返しについて扱う。といっても、他の言語と大きく変わる部分は、さほど無い。

まずはif文。

```js:bs04_01.js
// 以下のプログラムは 秋は夕暮れ と表示される
var season = "秋";

if(season == "春") {
  console.log("春はあけぼの");
} else if(season == "夏") {
  console.log("夏は夜");
} else if(season == "秋") {
  console.log("秋は夕暮れ");
} else if(season == "冬") {
  console.log("冬はつとめて");
} else {
  console.log("エラー：存在しない季節です");
}
```

### 比較演算子

| 演算子 | 説明 | 利用例 | 利用例の結果 |
|:---:|:---|:---|:---|
| == | 左辺と右辺が等しい場合はtrueになる | 3 == 3 | true |
| != | 左辺と右辺が等しくない場合はtrueになる | 3 != 2 | true |
| > | 左辺が右辺より大きい場合はtrueになる | 3 > 2 | true |
| < | 左辺が右辺より小さい場合はtrueになる | 3 < 2 | false |
| >= | 左辺が右辺以上の場合はtrueになる | 3 >= 3 | true |
| <= | 左辺が右辺以下の場合はtrueになる | 3 <= 3 | true |
| === | 左辺と右辺が等しく、なおかつデータ型も同じ場合はtrueになる | 3 === "3" | false |
| !== | 左辺と右辺が等しくない、もしくはデータ型が等しくない場合はtrueになる | 3 !== 2 | true |

### 論理演算子

| 演算子 | 説明 | 利用例 | 利用例の結果 |
|:---:|:---|:---|:---|
| && | 論理積。条件式がどちらもtrueになる場合はtrueになる | 3 == 3 && 4 == 4 | true |
| &#x7C;&#x7C; | 論理和。条件式のどちらかがtrueになる場合はtrueになる | 3 == 4 && 4 == 4 | true |
| ! | 否定。true・falseをひっくり返す | !(1 == 1) | false |

```js:bs04_02.js
/*
 * 18歳以上65歳未満かどうかを調べる。
 * 下記のプログラムでは OKです と表示される。
 */
var age = 25;

if(age >= 18 && age < 65) {
  console.log("OKです");
} else {
  console.log("禁じられています");
}
```

## switch文

JavaScriptにはswitch文もある。各caseの最後に `break` を入れないと、下のcaseの命令が実行されてしまうのも他言語と同じ。

```js:bs04_03.js
// このプログラムは 5 と表示される
var a = 3;
var b = 2;

var operator = "+";

switch(operator) {
  case "+":
    console.log(a + b);
    break;
  case "-":
    console.log(a - b);
    break;
  default:
    console.log("エラー：受け付けできない演算子です")
}
```

# 繰り返し

## while文

続いて繰り返し文。最初にwhile文から。

```js:bs04_04.js
// 1 から 10 までの和を求めるプログラム
var i = 1;
var sum = 0;

while(i <= 10) {
  sum += i;
  i++;
}

console.log(sum);    // 55 と表示される
```

※Firefoxのスクラッチパッドでは、ある程度の時間で処理が完了しない場合、「途中で処理を強制終了するか」を尋ねるダイアログが出る。無限ループをやってしまった場合は、それで止める。

## do-while文

JavaScriptではdo-while文も用意されている。

```js:bs04_05.js
// 1 から 10 までの和を求めるプログラム
var i = 1;
var sum = 0;

do {
  sum += i;
  i++;
} while(i <= 10);

console.log(sum);    // 55 と表示される
```

## for文

同じくfor文も用意されている。

```js:bs04_06.js
// 1 から 10 までの和を求めるプログラム
var i;
var sum = 0;

for(i = 1; i <= 10; i++) {
  sum += i;
}

console.log(sum);    // 55 と表示される
```

ここまでは、他言語のものと殆ど変わらない。

## for-in文

このfor-in文が多言語とは異なってくる部分になる。これは連想配列に用いる。他言語でいうイテレータのように、ループの最初で連想配列からキーを1つずつ取得して、ループの中で1件ずつ処理をする。ただし、キーを取得する順序は、JavaScriptの実行環境によっては保証されていないので注意。「格納した順」など何らかの順序で**実行環境に依らず確実に**ループを回したい場合は、やり方を考える必要がある。

```js:bs04_07.js
var colors = {
  "red"    : "赤",
  "blue"   : "青",
  "green"  : "緑",
  "yellow" : "黄色",
  "orange" : "オレンジ",
  "pink"   : "ピンク"
};

console.log("英語名 => 日本語名");

for(var key in colors) {
  console.log(key + " => " + colors[key]);
}
```

```text:bs04_07.jsの実行結果（一例）
英語名 => 日本語名
red => 赤
blue => 青
green => 緑
yellow => 黄色
orange => オレンジ
pink => ピンク
```

## breakとcontinue

JavaScriptの繰り返し処理でも `break` と `continue` が利用できる。途中でループを抜ける場合は `break` 、1回分の処理をスキップしてループの先頭に戻したい場合は `continue`。

```js:bs04_08.js
// 1から20までのうち偶数のみの合計を求める
var i = 0;
var sum = 0;

while(true) {        // 無限ループの形にしておく
  i++;

  if(i % 2 > 0) {
    continue;
  }
  
  if(i > 20) {
    break;
  }
  
  sum += i;
}

console.log(sum);    // 110 と表示される
```

# 補足：ブロック内の変数のスコープ
基本的にifやforのブロックの中で宣言された変数でも、そのブロックの外から参照**できてしまう**ので、注意。


```js:bs04_09.js
for(var i = 1; i <= 5; i++) {
  var a = 3;
  console.log("ループ" + i + "回目：" + a);
}

console.log("ループの外：" + a);
```

```text:bs04_09.jsの実行結果
ループ1回目：3
ループ2回目：3
ループ3回目：3
ループ4回目：3
ループ5回目：3
ループの外：3
```

# JavaScriptの関数の基本的な書き方

## 定義方法

JavaScriptにおける独自関数の記述方法は、以下のとおり。

```
function 関数名(引数) {
   ...（以下、処理内容を記載）...
}
```

CやJavaなどの言語と異なる点があるので、注意。

* 引数となる変数にデータ型の指定は不要（引数の場合は `var` も不要）
* 戻り値のデータ型の指定（および戻り値なしの指定）も不要。`function` キーワードのみ記述する
* 今まで観てきたとおりJavaScriptの命令は1行目から実行されるが、`function` を使って関数の定義をしている箇所の命令は、そのままでは実行されない。関数を呼び出して初めて実行される。
    * 関数の定義より上で関数を呼び出しても、問題なく実行される。

記述例を、以下に示す。

```js:bs04_10.js
funcA();                 // abc と表示される

var num = funcB(2, 3);
console.log(num);        // 5 と表示される

// 引数なし、戻り値なし
function funcA() {
  console.log("abc");
}

// 引数2つ、戻り値あり
function funcB(x, y) {
  return x + y;
}
```

## JavaScriptで用意されている組み込み関数

JavaScriptには標準で、最初から用意されている関数が、いくつかある。何らかのオブジェクトのメソッドではなく、「関数」。
詳細は、下記のページの「定義済み関数」欄を参照。

関数 - JavaScript | MDN
[https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions#定義済み関数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions#定義済み関数)

その中でも、以下の5つは良く使うものと思う。

| 関数名 | 説明 |
|:---|:---|
| parseInt | 文字列型→数値型（整数）に変換 |
| parseFloat | 文字列型→数値型（実数）に変換 |
| isNaN | 指定された演算結果の値が数値ではない型（NaN）かどうかを調べる |
| encodeURIComponent | 指定された文字列をURLエンコードする |
| decodeURIComponent | 指定された文字列をURLデコードする |

## 関数内の変数のスコープ

ifやforのブロック内で変数を定義しても、ブロックの外で参照できるのは先述のとおり。ただ関数内で定義された変数については、**その関数の中でしか参照されない**。

```js:bs04_11.js
var x = 10;        // グローバル変数x

function func() {
  x = 20;          // グローバル変数xを上書き
  var y = 30;      // ローカル変数y
  
  console.log(x);  // 20 と表示される
  console.log(y);  // 30 と表示される
}

func();
console.log(x);    // 20と表示される
console.log(y);    // この部分で 'yが見つからない' というエラーが発生する
```

```text:bs05_02.jsの実行結果
20
30
20
ReferenceError: y is not defined
```

また、グローバル変数と同じ名前の変数名の変数を、関数内で再度宣言することが可能。`var` をつければ再定義になり、`var`をつけなければグローバル変数の上書きになる。

なお、`var`をつけて再定義したローカル変数は、グローバル変数のそれとは別の存在となり、宣言した関数内でしか参照されない。

```js:bs04_12.js
var x = 10;        // グローバル変数x
var y = 20;        // グローバル変数y

function func() {
  var x = 30;      // グローバル変数xとは別のローカル変数xを宣言
  y = 40;          // グローバル変数yを上書き
  
  console.log(x);  // ローカル変数の x が参照され、30 と表示される
  console.log(y);  // 40 と表示される
}

func();
console.log(x);    // グローバル変数の x が参照され、10 と表示される
console.log(y);    // 40 と表示される
```

```text:bs05_03.jsの実行結果
30
40
10
40
```

### 補足：var をつけずに宣言した変数のスコープ

基本的には`var`をつけて変数を宣言するが、`var`をつけずに変数を宣言することも可能。その場合、その変数は、どこで宣言されてもグローバル変数となる。ただし、このような記述の仕方を多用するのは個人的には非推奨。

```js:bs04_13.js
var x = 10;        // グローバル変数x

function func() {
  y = 20;          // var をつけていないため、この y はグローバル変数
}

func();
console.log(x);    // 10 と表示される
console.log(y);    // この位置で参照可能。20 と表示される
```

# 次回予告

関数の応用