高階関数を書いたら、中級者になれた気がした。

## とあるWeb制作会社

社長「おーい、やめ太郎くん」

ワイ「何でっか？」

社長「お仕事を持ってきたで」
社長「**ある落語家さん**のWebサイトに組み込むスクリプトを作って欲しいんや」
社長「JavaScriptで**↓こんな関数**を作ってくれんか」

> + クラス名を指定してHTML要素のリストを取得。
> + その中で3番目、6番目、9番目、12番目・・・の要素の高さを  
200,000ピクセルに変更して、テキストを「アホ」に変更する。

ワイ「なるほど、**あの落語家はん**でっか」
ワイ「ええと、つまり3の倍数の要素たちの高さを・・・」
ワイ「に、**20万ピクセル!?**」
ワイ「**まあまあ長めのLP**より長いですやん」

社長「せや」
社長「関数の名前は`setHeight`で頼むわ」

ワイ「`setAho`ちゃうんですか」

社長「`setAho`はちょっと**ふざけ過ぎ**やから`setHeight`で頼むわ」

ワイ「なるほどですわ」
ワイ「**3の倍数**っていうことは関数名に含めないんでっか」

社長「何を言うてんねん、アホになるのは3の倍数って分かりきっとるやないかい」

ワイ「（今どき誰も知らんと思うけど）」

社長「使うときのイメージとしては↓こんな感じや」

```JavaScript
// クラス名を渡す
setHeight('list__item');
```

ワイ「ほうほう」
ワイ「何のために使うんか分かりまへんが、簡単ですわ！」
ワイ「お任せくださいやで！」

## さっそく作業開始

ワイ「クラス名を受け取って」
ワイ「それを元にHTML要素たちを取得するんやから」

```javascript
const setHeight = (className) => {
    const elements = document.getElementsByClassName(className);
```

ワイ「まずは↑こうやな！」
ワイ「ほんで・・・」

```javascript
    const elementsArray = Array.from(elements);
```

ワイ「↑こう、要素リストを配列に変換するんや」
ワイ「配列の**filterメソッド**を使いたいからな」
ワイ「ほんで・・・」

```javascript
    const targetElementsArray =
        elementsArray.filter((_, index) => (index + 1) % 3 === 0);
```

ワイ「↑こう、filterメソッドで3の倍数の要素たちだけを取得や」
ワイ「ほんで・・・」

```javascript
    targetElementsArray.forEach(element => {
        element.classList.add('tooHigh');
        element.innerHTML = 'アホ';
    });
```

ワイ「↑こう、`tooHigh`をクラスをつけてやるんや」
ワイ「これで高さが**20万ピクセル**になるんや」
ワイ「あと、ここでテキストも`アホ`に変更やな」

## もう完成

ワイ「社長！」
ワイ「`setHeight`関数、完成しましたやで！」

```javascript
const setHeight = (className) => {
    // クラス名からHTML要素たちを取得。
    const elements = document.getElementsByClassName(className);

    // filterメソッドを使うために、要素リストを配列に変換。
    const elementsArray = Array.from(elements);

    // 3の倍数の要素たちだけを取得。
    const targetElementsArray = elementsArray.filter((_, index) => (index + 1) % 3 === 0);

    // 取得した要素たちにtooHighクラスを追加＆テキスト変更。
    targetElementsArray.forEach(element => {
        element.classList.add('tooHigh');
        element.innerHTML = 'アホ';
    });
};
```

社長「おお、早いな！」
社長「おおきにやで！」

ワイ「てへへ・・・」

社長「でもスマン・・・」

ワイ「え・・・」

社長「一つだけ要件を言い忘れてたんや・・・」
社長「3の倍数の要素たちの・・・」

> + 
高さを20万ピクセルにして、  
テキストを「アホ」に変更して、  
**更に、文字色を赤くしたい場合もある**

社長「↑こういう要件やったんや・・・」

ワイ「Oh...」
ワイ「まあ、やってみますわ・・・」

## 修正開始

ワイ「文字色を赤くしたい**場合もある**、か・・・」
ワイ「ほな、使い方としては↓こんな感じのイメージにしてみよか・・・」

```javascript
// 通常の場合（通常とは）
setHeight('list_item');

// 更に文字色を赤くしたい場合
setHeight('list__item', true);
```

ワイ「第二引数に`true`を渡すと、文字色も変わるんや」
ワイ「せやから・・・」

```javascript
const setHeight = (className, changeColorToRed) => {
```

ワイ「↑こんな感じで第二引数を受け取ってやって・・・」

```javascript
    targetElementsArray.forEach(element => {
        element.classList.add('tooHigh');
        element.innerHTML = 'アホ';

        // 追加
        if (changeColorToRed === true) {
            element.style.color = 'red';
        }
    });
```

ワイ「第二引数の`changeColorToRed`が`true`だったら文字色を赤にするんや」

## またまた完成

ワイ「社長！」
ワイ「`setHeight`関数、完成しましたやで！」

社長「おお、爆速やんけ！」
社長「天才やな！」

ワイ「てへへ・・・」

社長「でもスマン・・・」

ワイ「**ファッ！？**」

**社長「一つだけ要件を言い忘れてたんや・・・」**

ワイ「（**一つちゃうやん・・・二つですやん・・・**）」

社長「3の倍数の要素たちの・・・」
社長「高さを200,000ピクセルにして、アホにして、赤くして」
社長「更に、透明にして見えなくしたい**場合もある**んや」

ワイ「**赤くしてから透明にするんかい**」
ワイ「どんな場合やねん」

社長「今後、官公庁なんかにもこのスクリプトを組み込む可能性があるんや」
社長「官公庁のサイトとかで使う場合は`アホ`とか不適切やからな」

ワイ「（どこの官公庁やねん）」
ワイ「（**何県やねん**）」
ワイ「・・・まあ、やってみますわ・・・」

## またまた修正開始

ワイ「ほな、今度は**第三引数**に`true`が入ってきてたら」
ワイ「透明にする、つまり`opacity`を`0`に変更する・・・」
ワイ「そんな感じにしてみよか」

```javascript
const setHeight = (className, changeColorToRed, toTransparent) => {
```

ワイ「↑こんな感じで第三引数の`toTransparent`を受け取ってやって・・・」

```javascript
    targetElementsArray.forEach(element => {
        element.classList.add('tooHigh');
        element.innerHTML = 'アホ';

        if (changeColorToRed === true) {
            element.style.color = 'red';
        }

        // 追加
        if (toTransparent === true) {
            element.style.opacity = 0;
        }
    });
```

ワイ「その`toTransparent`が`true`だったら透明にするんや」

## またまたまた完成

ワイ「社長！」
ワイ「`setHeight`関数、完成しましたやで！」

社長「・・・」
**社長「一つだけ要件を言い忘れてたんや・・・」**

ワイ「またかい！」
ワイ「一つちゃうやんけ！」
ワイ「○すぞ！」

社長「`許す`ってこと？」
社長「ありがとうやで・・・」

ワイ「・・・ギギギィ・・・！」
ワイ「もうええから要件を言うてみい！！！」

社長「3の倍数の要素たちの・・・」
社長「高さを変えてアホにして、色を赤くして・・・」
社長「透明にして・・・」
社長「**更に**・・・」

ワイ「**更に**・・・？」

社長「今後、色んなサイトでこのスクリプトを使えるようにやな・・・」
社長「色んなパターンに対応できる**ライブラリ**みたいにしたいんや・・・」
社長「せやから・・・」
社長「背景色を**緑**にしたい時もあるし、**青**にしたい時もあるし」
社長「文字サイズを**大きく**したい時もあれば、**小さく**したい時もある」
社長「要素をクリックしたら`アホ！`ってアラートが表示されるようにしたい時もあんねん」

ワイ「**どんなサイトや！！！**」
ワイ「**何のサイトや！！！**」

社長「ただ、**高さを20万ピクセル**にして**テキストをアホに変更**、それだけは**マスト**や」
社長「**その要件だけは固定や**」

ワイ「・・・はぁ・・・」
ワイ「・・・とりあえずやってみますわ・・・」

社長「すまんな・・・」

## またまたまた修正開始

ワイ「ええと、要件をまとめると・・・」

> + 要素の高さを20万ピクセルにする（マスト）
+ テキストを`アホ`にする（マスト）
+ 文字色を赤くする**かもしれない**
+ 透明にする**かもしれない**
+ 背景色も変更する**かもしれない**
+ 文字サイズも変える**かもしれない**
+ 要素にクリックイベントを設定したい**かもしれない**

ワイ「↑これを全部、**引数の渡し方**でコントロールすんのかいな・・・」
ワイ「引数、**何個必要やねん**・・・」

## こんな機能があったらいいのに

ワイ「もっとこう、**何をどうしたいか**を、**引数でそのまま**渡せたらいいのになぁ・・・」

ハスケル子「**できますよ**」

ワイ「マジかい、ハスケル子ちゃん！？」

ハスケル子「はい」
ハスケル子「**高階関数**にすればいいんです」

## 高階関数とは

ワイ「**後悔関数！？**」
ワイ「書いたことを**後悔**するような**クソコード**を書くってことかいな！？」

ハスケル子「私はそんなの書かないです」
ハスケル子「やめ太郎さんじゃないので」

ワイ「（**せやな**）」

ハスケル子「**高階関数**、つまり」
ハスケル子「関数を**引数として受け取る**関数や」
ハスケル子「関数を**戻り値として返す**関数のことです」

ワイ「関数が・・・関数を・・・受け取って・・・関数を・・・返す・・・？」
ワイ「怖い怖い怖い・・・」

ハスケル子「落ち着いてください」

ワイ「おお」
ワイ「字という人を飲み込んだら落ち着いたわ」

ハスケル子「そうですか」
ハスケル子「今回は**引数として関数を受け取る**パターンですね」
ハスケル子「こういうのは、やってみれば分かるので」
ハスケル子「とりあえずやってみましょう」

## まず、コールバック関数を書いてみる
ハスケル子「まず、**コールバック関数**を書いてみましょう」

ワイ「**キックバック**関数！？」
ワイ「その関数を誰かに紹介したら**いくらかお金がもらえるんか！？**」

ハスケル子「・・・**本当にそう思いますか？**」

ワイ「いえ、すんません」

ハスケル子「はい」

ワイ「そんで、コールバック関数って何ですか・・・」

ハスケル子「ええと」
ハスケル子「とりあえずですね」

## 追加でやりたいことを書いてみる

ハスケル子「`setHeight`関数は」
ハスケル子「3の倍数の要素たちに`tooHigh`クラスを追加して、テキストを変更する」
ハスケル子「その2つはどんな時も変わらない、マストな処理だって話ですよね」

ワイ「せや」

ハスケル子「そして、その後に追加で」
ハスケル子「透明にしたり、文字色を変えたり・・・」
ハスケル子「逆に変えなかったり・・・色々あるわけじゃないですか」

ワイ「せやね」

ハスケル子「その**追加でやりたい内容**を関数にしてみてください」

ワイ「やってみるわ・・・」

```javascript
const func = () => {
    element.style.backgroundColor = 'green';
    element.addEventListener('click', () => alert('アホ！'));
};
```

ワイ「↑こんな感じかな」
ワイ「色んなパターンがあって毎回違うみたいやけど」
ワイ「とりあえず今回は、**背景色を変更**して**クリックイベントを設定する**感じで書いてみたわ」

ハスケル子「いいですね」
ハスケル子「でも、`element`を引数に取る感じにしてもらっていいですか？」

ワイ「なるほど・・・」

```javascript
const func = element => {
    element.style.backgroundColor = 'green';
    element.addEventListener('click', () => alert('アホ！'));
};
```

ワイ「↑こんな感じ？」

ハスケル子「OKです」
ハスケル子「で、その`func`君を、第二引数として`setHeight`関数に渡してやるんです」

```javascript
setHeight('list__item', func);
```

ワイ「↑こんな感じ？」

ハスケル子「そうです」
ハスケル子「引数として渡されるこの`func`君こそが、**コールバック関数**です」

ワイ「なるほど・・・なんか分かってきたで・・・！」
ワイ「このあと`setHeight`関数を編集して」
ワイ「この変数を受け取るようにするんやな？」

ハスケル子「そうです」
ハスケル子「引数として入ってきた関数を」
ハスケル子「`setHeight`関数の中で使ってあげるんです」

ワイ「ってことは」

```javascript
const setHeight = (className, callback) => {
```

ワイ「↑こんな感じで、**callback**っていう名前で第二引数を受け取ってやって・・・」

```javascript
    targetElementsArray.forEach(element => {
        element.classList.add('tooHigh');
        element.innerHTML = 'アホ';

        // 変更した箇所
        if (callback) {
            callback(element);
        }
    });
```

ワイ「↑こうやな！」
ワイ「まず要素に`tooHigh`クラスを追加して、テキストを変更」

ハスケル子「はい」

ワイ「そのあと、もし第二引数の`callback`が存在した場合は」
ワイ「その`callback`に、引数として`element`を渡して実行してやれば・・・」
ワイ「`callback`の中身はさっきの`func`君やから・・・」
ワイ「`element`の**背景色が変更**されて**クリックイベントも設定**されるんやな！」

ハスケル子「そうです！」
ハスケル子「**何をどうしたいのか**をそのまま引数で渡せるので」
ハスケル子「**単純な引数**だけではやりづらいときに便利です」

ワイ「おお・・・」
ワイ「パラメーターいっぱい増やすより、やりたいことを**そのまま引数にできる**感じで素敵やん・・・！」

ハスケル子「そうです」
ハスケル子「ちなみに`func`君はここでしか使わない関数なので」
ハスケル子「わざわざ`func`と名前をつけないでもいいかもですね」

ワイ「なるほど」

```javascript
setHeight('list__item', element => {
    element.style.backgroundColor = 'green';
    element.addEventListener('click', () => alert('アホ！'));
});
```

ワイ「↑こういうことやな」

ハスケル子「ですね」
ハスケル子「要は・・・」

> 「**ほとんど共通**の処理を何回も書いてるなぁ」
> 「そうだ、関数にして共通化しよう」

ハスケル子「ってなったときに」

> 「うーん、**ほとんど共通処理で済む**んだけど」
> 「処理の途中で少しだけ**挙動を自由にコントロールしたい**なぁ」

ハスケル子「とか思ったときに便利ですね」

ワイ「なるほどなぁ・・・！」

## 今度こそ完成

ワイ「社長！」
ワイ「`setHeight`関数、完成しましたやで！」

**社長「一つだけ要件を言い忘れてたんや・・・」**
社長「背景画像を変更したい場合もあるんや・・・」

ワイ「**もう何でも来いですわ！**」
ワイ「**何をどうしたいか**を**そのまま引数として**渡せるようになったワイに」
ワイ「もはや**死角なし**ですわ！！！」

社長「おお、流石やな」

ワイ「**高階関数**を、**コールバック関数**に渡すんですわ！」

ハスケル子「やめ太郎さん、**逆です**」
ハスケル子「**コールバック関数**を、**高階関数**に渡すんです」
ハスケル子「引数として**コールバック関数**を渡す」
ハスケル子「その**コールバック関数を**、引数として受け取るのが**高階関数**です」

ワイ「Oh...」
ワイ「逆やったか」

社長「**後悔関数！？**」
社長「書いたことを後悔するような（以下略）」

ハスケル子「（こいつも同じ発想か）」
ハスケル子「（なんだこの時間）」

## なんだかんだで終業時刻

ワイ「ハスケル子ちゃん、今日もありがとうな」

ハスケル子「いえいえ」

ワイ「高階関数って楽しいな」
ワイ「**何をしたいか**をそのまま引数として渡せるのが、何か素敵やわ」

ハスケル子「でも、やめ太郎さんだって当たり前に使ってるんですよ」
ハスケル子「さっき普通に使ってたforEach、filter、addEventListenerなんかも」
ハスケル子「関数を受け取る関数なので**高階関数**ですよ」

ワイ「おお、ほんまや」

ハスケル子「他には、アニメーション系のライブラリなんかも高階関数である事が多いですよ」
ハスケル子「Slickとか、jQueryのanimateとか」

ワイ「そうなんか」

ハスケル子「アニメーションし終わった後に**何らかの処理をしたい**なんてこと、よくあるじゃないですか」

ワイ「ああ、あるわ」

ハスケル子「でも、その**何らかの処理**ってケースバイケースなので、単純な引数では表現できないんですよ」

ワイ「そらせやな」

ハスケル子「だから、その何らかの処理を**関数で表現**してやって、それを引数として渡す・・・」
ハスケル子「そういう使い方のライブラリは結構あります」
ハスケル子「Wikipediaの[**クロージャ**](https://ja.m.wikipedia.org/wiki/クロージャ)の項目にも───」

> ライブラリの設計者は、関数（コールバック関数）を引数として受け取る関数（高階関数）を定義することで、**利用者が挙動をカスタマイズできる**汎用的なライブラリ関数を提供することができる。

ハスケル子「───なんてことが書いてあります」

ワイ「なるほどな〜」
ワイ「今日ワイも高階関数を書いてみたから、なんだか**フロントエンド中級者**になったような気がするわ」

ハスケル子「へえ」
ハスケル子「やめ太郎さん、分割代入ってしたことあリますか？」

ワイ「ん？ないけど」

ハスケル子「Webpackの使い方は？」

ワイ「知らん・・・」

ハスケル子「React Hooksは？」

ワイ「何それ・・・」

ハスケル子「ですよね」
ハスケル子「やめ太郎さんは、中級者ですか？」

ワイ「**いえ、初級者です・・・**」
ワイ「申し訳ございませんでした・・・」

## 結論
中級者になれた**気がした**だけでした。
**気のせいでした。**

**〜おしまい〜**