【JS】高階関数をざっくりと理解してみる

高階関数について簡単に言語化してみました。

## 高階関数とは
高階関数とは、一言で説明すると「関数を受け取ったり関数を返す関数」のことです。
噛み砕くと、

・引数として関数を受け取る

・戻り値に関数を指定する

関数になります。

ちょっとイメージしづらい、、、。
簡単ですが高階関数のコードを書いてみます。

```higher-order-function.js
//高階関数を定義します。
//桃鉄ののぞみカードをイメージ笑
function nozomiCard(f) {
    let total = 0;
    for(let i = 0; i < 5; i++) {
        total += f();
    }
    return total;
}

//高階関数の引数となる関数を定義します。
//1~6の数字を返却
function dice() {
    const resultNum = Math.floor(Math.random() * 6) + 1;
    return resultNum;
}

nozomiCard(dice);
```
まず、高階関数のnozomiCardを定義しています。
この関数の引数`f`は関数を受け取ります。（今回はdiceを渡しています。）
受け取った関数`f`実行し、実行結果を変数totalの中に格納しています。
これをループで５回行い合計の値を戻り値として返却しています。

この時の私的注意ポイントは`関数の実行ではなく、関数を渡す`ことです。

::: note info
関数を渡す。
nozomiCard(dice);
:::

::: note warn
関数を実行してしまう。
nozomiCard(dice());
:::

関数の実行をしてしまうと、関数diceの実行結果（数字の１〜６）が引数として渡されてしまい、
想定している結果が得られません。

最初は関数を渡すということが違和感がある方は、
`関数もオブジェクトの一種`で、`値の一種`だ！！
という感覚を持ってください。
すんなり高階関数が理解できるようになると思います。
（一度関数をconsole.dirで確認すると理解が深まるかもしれません。）




## よく使用する（よく見る）高階関数
よく使用する（よく見る）高階関数に`forEach`, `map` `filter`, `every`, `some`, `sort`, `reduce`があります。

### forEach
・__コールバック関数を受け取り、配列の要素毎に関数を呼び出します。__

`forEach(function(element, index, array) { /* … */ }, thisArg)`

`element`
現在処理されている配列の要素です。
`index`
配列内の element の添字です。
`array`
forEach() が呼び出されている配列です。
`thisArg` 省略可
コールバック関数内で this として使用する値です。

``` forEach.js
const nums = [2,4,6,8];
nums.forEach(function(element) {
    console.log(element * element);
    // 4, 8, 12, 16
}); 
```
個人的にはforEachよりもfor ofの方がよく使うような気がしてます。

### map
・__コールバック関数を配列要素毎に呼び出し、その結果からなる新しい配列を生成します。__

`map(function(element, index, array) { /* … */ }, thisArg)`

`element`
配列内で現在処理中の要素です。
`index`
現在処理中の要素の配列内における添字です。
`array`
map が呼び出された配列です。
`thisArg`省略可
コールバック関数を実行するときに this として使う値です。

```map.js
const nums = [2,3,5,18];
const doubleNums = nums.map(function(element) {
    return element * 2;
});
nums; //[2,3,5,18]
doubleNums; //[4,6,10,36]
```

forEachとの違いは、mapは新しい配列を生成します。

### filter
・__提供されたテスト関数を満たす要素から新しい配列を生成します。__

`filter(function(element, index, array) { /* … */ }, thisArg)`

`element`
配列内で処理中の現在の要素です。
`index`
配列内で処理中の現在の要素の位置です。
`array`
filter() が呼び出された配列です。
`thisArg 省略可`
コールバック関数を実行するときに this として使用する値です。

```filter.js
conts nums = [1,2,3,4,5,6,7,8,9,10];
const evenNumber = nums.filter(function(element) {
    return element % 2 === 0;
});
evenNumber; // [2,4,6,8,10]
```
提供されたコールバック関数はtrueかfalseを返します。
trueであればelementはfilterされた新しい関数（evenNumber）に追加されます。
filterなのでtrue を返した要素は残され、false を返した要素は取り除かれます。の方が正しいかも、、、。

### every
・__配列内の`全ての要素`が指定されたテスト関数を満たすかどうかをtrue,falseで返す。__

`every(function(element, index, array) { /* … */ }, thisArg)`

`element`
現在処理されている要素です。
`index`
現在処理されている要素の添字です。
`array`
every が実行されている配列です。
`thisArg` 省略可
コールバック関数を実行するときに this として使用すされる値です。

```every.js
const nums = [2,4,5,7];
nums.every(function(element) {
    return element % 2 === 0;
}); // false

const nums2 = [2,4,6,8];
nums2.every(function(element) {
    return element % 2 === 0;
}); // true
```

### some
・__１つでもテスト関数を満たす要素があればtrueを返す。__

`some(function(element, index, array) { /* … */ }, thisArg)`

`element`
配列内で現在処理中の要素です。
`index`
現在処理中の要素の配列内における添字です。
`array`
some が呼び出された配列です。
`thisArg`省略可
コールバック関数を実行するときに this として使う値です。
```some.js
const nums = [1,2,3,4,5];
nums.some(function(element) {
     return element % 2 === 0;
}); // true

const nums2 = [1,3,5,7];
nums2.some(function(element) {
     return element % 2 === 0;
}); // false
```

### sort
・__ソート順を定義する関数を指定し、辞書順にソートを行います。__
・__ソート順を定義する関数が省略された場合、各文字の Unicode コードポイント順に従ってソートされます。__


`sort(function compareFn(a, b) { /* … */ })`

`a`
比較する第一要素。

`b`
比較する第二要素。

| compareFn(a, b) の返値    | ソート順    |
|:-:|:-:|
|  > 0 |  `a` を `b` の後に並べる |
|  < 0 |  	`a` を `b` の前に並べる |
| === 0  |  `a` と `b` の元の順序を維持する |

```sort.js
let nums = [5,8,7,6];
let ascOrder = nums.sort(function(a, b){
  return a - b; //昇順
});

ascOrder; //[5, 6, 7, 8]

let discOrder = nums.sort(function(a, b){
  return  b - a; //降順
});

discOrder; //[8, 7, 6, 5]
```
コピーは作成されず、ソートを実行した配列自体がソートされるため、注意が必要です。

### reduce
・__配列の各要素に対して（引数で与えられた）reducer関数を実行して「単一の出力値」を生成します。__

`reduce(function(previousValue, currentValue, currentIndex, array) { /* … */ }, initialValue)`

`previousValue`
前回の callbackFn の呼び出し結果の値です。初回の呼び出しでは initialValue が指定されていた場合はその値、そうでない場合は array[0] の値です。
`currentValue`
現在の要素の値です。初回の呼び出しでは initialValue が指定された場合は array[0] の値であり、そうでない場合は array[1] の値です。
`currentIndex`
currentValue の位置です。初回の呼び出しでは、 initialValue が指定された場合は 0、そうでない場合は 1 です。
`array`
走査する配列です。
`initialValue` 省略可
コールバックが初めて呼び出されたときの previousValue の初期値です。 

```reduce.js
//配列内の合計値を求める
const nums = [3,5,6,7,8];
const result = nums.reduce(function(previousValue, currentValue){
    return previousValue + currentValue;
});
result; //29

//配列内の最大値を求める
const maxNum = nums.reduce(function(max, currentValue){
    if(max < currentValue) {
        return currentValue;
    }
});
maxNum; //8
```

上記の配列内の合計値を求める場合は、以下のようにreduceが実行されています。
| Callback | previousValue | currentValue | return value |
|:-:|:-:|:-:|:-:|
|  1回目 |  3  |  5 |  8  |
|  2回目 |  8  | 6  | 14  |
|  3回目 |  14 | 7  | 21  |
|  4回目 |  21 | 8  | 29  |

上記の配列内の最大値を求める場合は、以下のようにreduceが実行されています。
| Callback | max | currentValue | return value |
|:-:|:-:|:-:|:-:|
|  1回目 |  3  |  5 | 5  |
|  2回目 |  5  |  6 | 6  |
|  3回目 |  6  |  7 | 7  |
|  4回目 |  7  |  8 | 8  |

reduceはこれら以外にも様々な場面で使用することができます。
使い勝手はいいですが、私はまだまだ使いこなせていません泣

## まとめ
・高階関数とは、「関数を受け取ったり関数を返す関数」のこと。
・関数もオブジェクトの一種で、値の一種だ！

## 参考
MND Web Docs
https://developer.mozilla.org/ja/