【JavaScript】関数と宣言① 〜関数の宣言・呼び出し・引数〜


# 概要
...『[【JavaScript】関数と宣言② 〜関数式・アロー関数・コールバック関数〜](https://qiita.com/andota05/items/0f6ed255d1c84de82c4d)』もあります。

JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* 関数の宣言・定義方法
* 関数の呼び出し方法
* 関数の引数

# 関数と宣言
* 関数とは、ある一連の手続きを`1つの処理としてまとめる機能`のこと。
* 一度定義した関数を呼び出すことで同じ処理を何度も実行できる。

## 関数の宣言方法
* JavaScriptで関数を定義するには、`function`キーワードを使用する。<br>(これで「今から記載するプログラムは関数なんだな」とJavaScriptが認識してくれる)
* `function`から始まる文を`関数宣言`と呼ぶ。

```js
// function 関数名( 仮引数 ※任意 ) { 処理内容 }で関数を定義
function testFunc(value) { console.log("testFuncを実行"); }
```
上記のように横1行に記述しても問題ないが、
大体の場合`{ }`内の処理は複数、もしくは長くなるため、改行を含めて定義すると`可読性`が上がる。

## 関数の要素
関数を構成する要素として、以下4つの要素が存在する。

**1. 関数名**
・ 利用できる名前は変数名の命名規則と同じ(変数の命名規則については[こちらの記事](https://qiita.com/andota05/items/238ff472a0e711b65275)をご参照ください)

**2. 仮引数**
・ 関数に渡す値が入る変数
・ 複数ある場合はカンマ`(,)`で区切る

**3. 処理内容(関数の内容)**
・`{ }`で囲んだブロックの中に実行したい処理の内容を記載する

**4. 返り値**
・ 関数が計算や処理した実行結果のこと
・ `return文`で実行結果を返すことができる
・ 返り値は必須ではないため、関数で実行結果を返す必要がない場合は、retrun文を省略可能
・ 省略した場合、未定義という意味の`undefined`という結果が返される
・ また、return文以降の処理は実行されないため、処理の記載に注意が必要

```js
// 関数を作成
function double(number) {          // => 1.関数名は「double」、2.仮引数は「number」
    const result = number * 2;     // => 3.処理内容は「仮引数に与えられた値に2をかけて変数resultに代入」
    return result;                 // => 4.返り値は「計算結果が代入された変数result

    console.log("return以降の処理"); // return以降の処理のため、実行されない
}

// 返り値がない関数を定義する場合は、returnを省略可能
function neverFunc() {
  console.log("戻り値がない関数です")
}
```

> **★POINT「仮引数と(実)引数」**
> ・仮引数は関数定義時に設定しておく引数のこと。
> ・(実)引数は関数を実際に呼び出す際に渡す・渡される値のこと。

## 関数の呼び出し方
* 作成した関数、もしくはJavaScriptが元々用意している関数(console.log()など)を使用し、処理を実行することを`関数を呼び出す`と表現する。
* それぞれ`関数名();`で呼び出せる。

先ほどの例で作成した関数double( )に引数「2」を渡し、呼び出してみる。

```js
// 仮引数を持った関数を定義
function double(number) {
  const result = number * 2;
  return result; 
};

// 関数doubleの引数に2を指定して呼び出し、関数の返り値を出力する
console.log(double(2)); // => 4
```

## 関数の引数
* 関数に定義した`仮引数の個数`と`実際に呼び出した際の引数の個数`が違っても、関数を呼び出せる。
* 引数が省略されたときに、デフォルトの値を指定する`デフォルト引数`という構文も存在する。

### 呼び出し時の引数が少ないとき
* 定義した関数の仮引数よりも呼び出し時の引数が少ない場合、余った仮引数には`undefined`という値が代入される。

```js
// 仮引数「number」を持ち、与えられた引数を返す関数を定義
function argFunc(number) {
    return number;
};

console.log(argFunc());
// => undefined(引数を指定せずに関数を実行できる)

// 仮引数「name」「age」の二つを持ち、与えられた引数を配列で返す関数を定義
function arrayFunc(name, age) {
    return [name, age];
}

console.log(arrayFunc('Taro'));
// => ['Taro', undefined](一部引数を指定せずに関数を実行できる)
```

### 呼び出し時の引数が多いとき
* 関数の仮引数に対して引数の個数が多い場合、あふれた引数は単純に無視される。

```js
// 仮引数「number」を持ち与えられた引数を返す関数を定義
function argFunc(number) {
    return number;
};

console.log(argFunc(1, 2, 3)); // => 1(引数に指定した「2,3」は無視され、最初に指定した「1」のみ返される)
```

### デフォルト引数
* 仮引数に対応する引数が渡されていない場合に、デフォルトで代入される値を指定できる。
* 複数指定する場合は、カンマ`(,)`で区切る。
* `ES2015`から導入された。

```js
//function 関数名(仮引数 = デフォルト値){ 処理内容 };でデフォルト値を設定
function arrayFunc(name = '名無しさん', age = '未設定') {
    return [name, age];
}

console.log(arrayFunc()); // => ['名無しさん', '未設定']
```

## 可変長引数
* 固定した数ではなく任意の個数の引数を受け取れる引数を`可変長引数`と呼ぶ。
* `Rest parameters(ES2015〜)`か、関数の中でのみ参照できる`arguments`という特殊な変数を利用する。

### Rest parameters
* 仮引数名の前に`...`を付けた仮引数のこと(残余引数とも呼ばれる)
* 関数に渡された値が`配列`として代入される。
* 通常の仮引数との組み合わせも可能だが、Rest parametersは`末尾`に指定する必要がある。
* `ES2015`から導入された。

```js
// 引数に指定された値を返す関数を定義し、仮引数名の前に...をつける
function numberFunc(...numbers) {
    console.log(numbers);
}

// 通常の仮引数が１つとRest parametersを持つ関数を定義
function nameNumberFunc(name, ...numbers) {  // Rest parameters(...)は末尾に指定
    console.log(name);
    console.log(numbers);
}

// 任意に指定した値が配列として扱われていることが確認できる
numberFunc(1);        // => [1]
numberFunc(1, 2);     // => [1, 2]
numberFunc(1, 2, 3);  // => [1, 2, 3]
nameNumberFunc(1, "Taro", "Hanako", "Goro");  // => 1
                                              // =>  ['Taro', 'Hanako', 'Goro']
```

### arguments
* 関数の中でのみ参照できる特殊な変数、オブジェクトのこと。
* 配列のようにインデックスで要素へアクセスできるのが特徴。(Arrayオブジェクトのメソッドは利用できない)

※Rest parameters(ES2015〜)が利用できる環境では、非推奨となっているため詳細は割愛。

## 関数の引数と分割代入
* 関数の引数も`分割代入`が可能。
* 分割代入はオブジェクトや配列からプロパティを取り出し、変数として定義し直す構文。<br>★[オブジェクトの分割代入に関する記事はこちら](https://qiita.com/andota05/items/86f359455eb4a233031a)
* `ES2015`から導入された。

```js
// オブジェクトのプロパティ「name」をコンソールへ出力する関数を作成
function callUser({name, age}) {
    console.log(name);
    console.log(age);
}

// userオブジェクトを作成
const user = {
    name: "Taro",
    age: 21
};

// 関数callUserに引数としてuserオブジェクトを渡す
callUser(user);
// => Taro(nameプロパティを取り出せていることが分かる)
// => 21(ageプロパティを取り出せていることが分かる)
```