[Javascript] コールバック関数のおさらい

# はじめに
Javascriptでコーディングする時避けて通れないのが非同期処理の実装です。
今回Javascriptで非同期処理を行う際に使用するコールバック関数について復習したのでメモとして残しておきます。
同じようにコールバックの仕組みでつまづいている方の参考になれば嬉しいです。

# コールバック関数とは
「コールバック関数とは」でググると、次のように出てきます。

> コールバック関数は他の関数に引数として渡される関数で、外側の関数で何らかの処理やアクションを実行します。
> 引用元: [MDM Web Docs](https://developer.mozilla.org/ja/docs/Glossary/Callback_function)

これだけだと正直意味が分からないので、順を追ってコールバック関数を作成してみます。

# コールバック関数を作成
### 関数とは
そもそもJavascriptにおける関数(function)とは何かからみてみます。

実はこれが一番重要なんですが、
Javascriptでは関数(function)も**値**です。

つまり、Number型やboolean型と同様、functionも値です。
なので変数に代入することも出来ます。

```javascript
// Number
let num = 1;
// Boolean
let is_num = true;
// function
let sum = function(a, b){
	console.log(a + b);
}
```

### 型を確認
試しに適当な関数を作成し、typeofで型を確認してみます。

```javascript
// callbackという名前の関数を定義
function callback() {
    console.log('I am callback');
}

// typeofで型を確認
console.log(typeof callback);
```
```bash:実行結果
> function
```

関数名をtypeofで確認すると、function型であることがわかります。
つまり関数は、()が付くと関数として実行されるが、()を付けていない時はfunction型の値として扱われるということです。

### 関数を別の関数に渡す
なので関数はNumber型やBoolean型同様、別の関数に引数として渡すことが出来ます。
上で変数に格納したそれぞれの型を別の関数の引数として渡してみます。

```javascript
// 引数を受け取る関数を定義
function another_func(param){
    console.log(param);
}

let num = 1;
let is_num = true;
let sum = function(a, b){
	console.log(a + b);
}

// 関数を実行
another_func(num); // Numberを渡す
another_func(is_num); // Booleanを渡す
another_func(sum); // functionを渡す
```
```bash:実行結果
> 1
true
[Function: sum]
```
関数は値として別の関数に渡されています。

### 渡した関数を実行
先ほど関数は()を付けることで関数として実行されると書きました。
次に値として渡した関数を渡された関数内で実行してみます。

```javascript
// 関数を引数で受け取り、内部で実行する関数を定義
function another_func(func){
    // 受け取った関数(値)を実行
	func();
}

// 引数として渡す関数を定義
let callback = function(){
	console.log('Hello I am callback function');
}

// 実行
another_func(callback);
```
```bash:実行結果
> Hello I am callback function
```
callbackという変数に格納された関数(値)をanother_funcが受け取り、関数内で実行しています。
これはanother_func()を実行する際、引数にcallbackを()をつけず値として渡し、another_funcの中で()をつけ実行しています。
つまりcallbackは別の関数に呼ばれることで実行される関数です。
このように別の関数に呼ばれることで実行できるようになる関数をコールバック関数と言います。

ちなみに呼び出す側、ここではanother_funcのように別の関数を引数として受け取り、自らの内部で実行する関数を高階関数と言います。

最初にコールバック関数とはで見た、
> コールバック関数は他の関数に引数として渡される関数で、外側の関数で何らかの処理やアクションを実行します。

の意味がだいぶ分かってきました。

### 無名関数を渡す
また高階関数に引数として渡す関数には名前が無くても大丈夫です。

```javascript
function another_func(func){
    // 受け取った関数の値を実行
    func();
}

// 実行
another_func(function(){
	console.log('Hello I am callback function, but no name');
});
```
```bash:実行結果
> Hello I am callback function, but no name
```
上では一度callbackという関数を定義しましたが、今回は関数のパラメーターで関数を直接定義しています。
another_funcをthenに置き換えると見覚えがある形ですね。

### 引数を渡す
またコールバック関数には引数も渡せます。

```javascript
function another_func(func){
	let greeting = 'Hello I am callback function have a param';
	func(greeting);
}

another_func(console.log);
```
```bash:実行結果
> Hello I am callback function have a param
```
公開関数内で実行するコールバック関数への引数を指定し渡しています。
だいぶ見覚えのある形です。Promiseやajaxのthen()ではこのような処理が行われていたんですね。

### 結論
コールバック関数とは、
・高階関数内で実行される(実行したい)関数
・予め定義しておいても良いし、無名関数として渡しても良い
・高階関数に渡す際には()をつけず値として渡す
・公開関数内で実行する時に引数を受け取れる
こんな特徴の関数です。


# おわりに
今まで何となくコールバック関数を使っていましたが、仕組みを辿ると面白いですね。
実際にコールバック関数がどのように実装されているのか仕組みを知っていればより洗練されたコードが書けそうですよね。
次はPromiseやasync awaitについても書ければ良いなと思います。


# 参考サイト
[JavaScriptの「コールバック関数」とは一体なんなのか](https://sbfl.net/blog/2019/02/08/javascript-callback-func/)
めちゃくちゃ分かりやすいサイトです。
今回コールバック関数やPromise等の非同期処理を調べる際、すごく参考になりました。ありがとうございました。