【JavaScript】関数について

##はじめに
JavaScriptの基礎を勉強したらとても良い学びになったのでメモ第2弾です
JavaScriptの関数についてです

ちなみに1回目はこちら↓

https://qiita.com/komekami0131/items/7cdf7cc7bacc11779cc5

こちらの本を参考にさせていただきました

https://www.amazon.co.jp/%E6%94%B9%E8%A8%82%E6%96%B0%E7%89%88JavaScript%E6%9C%AC%E6%A0%BC%E5%85%A5%E9%96%80-%EF%BD%9E%E3%83%A2%E3%83%80%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AB%E3%82%88%E3%82%8B%E5%9F%BA%E7%A4%8E%E3%81%8B%E3%82%89%E7%8F%BE%E5%A0%B4%E3%81%A7%E3%81%AE%E5%BF%9C%E7%94%A8%E3%81%BE%E3%81%A7-%E5%B1%B1%E7%94%B0-%E7%A5%A5%E5%AF%9B-ebook/dp/B01LYO6C1N/ref=sr_1_5?dchild=1&keywords=javascript&qid=1623279484&sr=8-5

##概要
###関数とは：
与えられた入力に基づいてなんらかの処理を行い、その結果を返す仕組み

関数には以下の2種類がある

* **標準関数**：JavaScriptが標準で提供する関数
* **ユーザー定義関数**：自分で定義した関数

今回は、ユーザー定義関数についてフォーカスします

##ユーザー定義関数の定義方法
ユーザー定義関数の定義方法は以下の4種類

1. function命令で定義する
2. Functionコンストラクター経由で定義する
3. 関数リテラル表現で定義する
4. アロー関数で定義する

###1. function命令で定義する
関数を定義するのに基本的なアプローチ

function 関数名(引数,…){
	…任意の処理…
	return 戻り値;
}

```javascript
function getTriangle(base,height) {
	return base * height / 2;
}
console.log('三角形の面積：' + getTriangle(5, 2));
```

関数名をつける際には、

* （単なる文字列ではなく）識別子の条件を満たす必要がある
* 「その関数がどのような処理を担っているのか」がすぐわかるような名前を付ける
ex) 「showMessage」のように「動詞＋名詞」の形式が一般的
		
###2. Functionコンストラクター経由で定義する
組み込みオブジェクトであるFunctionオブジェクトのコンストラクターを利用する方法

var 変数名 = new Function(引数,…,関数の本体);

```javascript	
var getTriangle = new Function('base', 'height', 'return base * height / 2;');
console.log('三角形の面積：' + getTriangle(5, 2));
```
	
Functionコンストラクターでは、引数や関数本体を文字列として定義できる
特別な理由がない限り、利用するメリットはない

###3. 関数リテラル表現で定義する（匿名関数）
JavaScriptにおいて関数はデータ型の一種
したがって、

* 文字列や数値と同じく、リテラルとして表現できる  
* 変数に代入できる
* 戻り値として関数を返すことができる

```javascript
var getTriangle = function(base, height) {
	return base * height / 2;
};
cosole.log('三角形の面積：' + getTriangle(5, 2));
```

**function命令との違い**

* function命令 → 関数getTriangleを直接定義している
* 関数リテラル → 「function(base,height) {…}」と名前のない関数を定義したうえで、変数getTriangleに格納している
		
###4. アロー関数で定義する
アロー関数ではfunctionキーワードを書かず、アローで引数と関数本体をつなぐ

(引数,…) => {…関数の本体…}

```javascript	
let getTriangle = (base, height) => {
	return base * height / 2;
};
console.log('三角形の面積：' + getTriangle(5, 2));

let getTriangle = (base, height) => base * height / 2;
```

##スコープ

* 関数の外で宣言した変数 → **グローバル変数**
* 関数の中で宣言した変数 → **ローカル変数**

スコープが異なる場合、それぞれの変数は同名であっても別物として認識される

```javascript:例
var scope = 'Global Variable';

function getValue() {
  var scope = 'Local Variable';
  return scope;
}

console.log(getValue()); // Local Variable
console.log(scope); //Global Variable
```

>###var/let/constの使い分け
|  | var | let | const |
|:-:|:-:|:-:|:-:|
| 再宣言  | 〇  | ×  | ×  |
| 再代入  | 〇  | 〇  | ×  |
| スコープ  | 関数  | ブロック  | ブロック  |
| ホイスティング  | undefined  | エラー  | エラー  |

>**再宣言**：一度宣言した変数を同じ変数名で宣言しなおすこと
>>再宣言できるvarでは予期しない再宣言が起こりうる
let/constで再宣言した場合、エラーになる

>**再代入**：宣言した変数に値を設定しなおすこと
>>var/letでは値が再代入される
constで再代入した場合、エラーになる

>**スコープ**
>>varはブロックスコープ（{}で囲われた部分）が適用されない
const/letはブロックスコープが適用される

>**ホイスティング**：変数宣言が常に関数の先頭で行われたことにされる挙動
>
>**基本的にはconstで定義**
**数え上げのみlet（constは値を変えられないため）**
**varは使わない**

##再帰関数
**自分自身を呼び出す関数**

階乗計算のように同種の手続きを何度も呼び出すような処理をコンパクトに表現できる

以下は、自然数nの階乗がn×(n-1)!で求められることを利用した例

```javascript:再帰関数
function factorial(n) {
  if(n!=0) { return n*factorial(n-1); }
  return 1;
}

console.log(factorial(5)); // 120
```

##高階関数
関数はデータ型の一種であるJavaScriptの特性から、**関数を引数、戻り値として扱う関数**

以下は、配列dataの内容を指定されたユーザー定義関数fの規則に従って、順番に処理するための高階関数

```javascript:高階関数
var ary = [1, 2, 4, 8, 16];

// 高階関数
function arrayWalk(data, f) {
  for(var key in data) {
    f(data[key], key);
  }
}

// 配列を処理するためのユーザー定義関数
function showElement(value, key) {
  console.log(key + ':' + value);
}

// 第二引数にshowElement
arrayWalk(ary, showElement);
//0:1 1:2 2:4 3:8 4:16
```
>コールバック関数：呼び出し先の関数の中で呼び出される関数（上記ではshowElement関数）
あとで呼び出されるべき処理、という意味

【メリット】
大枠の機能（上記ではarrayWalk関数）だけを定義しておいて、詳細な機能の関数（上記ではshowElement関数）は利用者が自由に決めることができる

###高階関数で匿名関数を利用する
高階関数において、引数として与えられる関数は「その場限り」でしか利用されないことがよくある
→**匿名関数（関数リテラル）として記述する**

先ほどのコードを匿名関数で書き換えると…

```javascript:高階関数を匿名関数で利用
var ary = [1, 2, 4, 8, 16];

// 高階関数
function arrayWalk(data, f) {
  for(var key in data) {
    f(data[key], key);
  }
}

// 第二引数にshowElement
arrayWalk(
  ary,
  function (value, key) {
    console.log(key + ':' + value);
  }
); 
```

【メリット】

* 関連する処理が1つの文で記述できる
→呼び出し元と実際の処理を規定している関数との関係がわかりやすくなり、コードが読みやすくなった

* 関数に名前をつけずにすむ
→意図せぬ名前の重複を回避できる

##さいごに
JavaScriptでの基本的な関数について勉強し、まとめてみました

高階関数の部分は理解が曖昧だったのでとても勉強になりました

このほかにも、参考にさせていただいた書籍では深堀りし解説しているので、気になった方はチェックしてみてください

##参考

https://qiita.com/cheez921/items/7b57835cb76e70dd0fc4