JavaScriptのbindをループ処理で定義していくヘルパー関数書いてみたンゴね〜

こんにちは！(๑╹ω╹๑ )

JavaScriptで可変メソッドを用いて動的に型のバリデーションを行う実装を前回の記事で紹介したばかりですが、
今日はbindをループ処理で立ち回る実装についてお話します👨‍💻

前回の記事：[Non TypeScriptスタックで型のバリデーションをする機構を01で実装してみる](https://qiita.com/huuya/items/a133497fa1a7cba192d7)

## bindをループ処理で定義する

まずは結論から🙌
↓の関数です！

```js
const binds = (methods, self) => {
    const result = {};
    for (const method of methods) {
        result[method] = self[method].bind(self);
    }
    return result;
};
```

※ [個人開発](https://github.com/huuyafwww/harver/pull/6#pullrequestreview-483025015)で実装したものをそのまま流用しています

この`binds`関数はこんな時に使います🤔

```js
class Hoge{
  constructor() {
    this.onClick = this.onClick.bind(this);
    this.onChange = this.onChange.bind(this);
    this.onKeyUp = this.onKeyUp.bind(this);
    this.onKeyDown = this.onKeyDown.bind(this);
    this.onHover = this.onHover.bind(this);
    this.onActive = this.onActive.bind(this);
  }

  onClick(){}
  onChange(){}
  onKeyUp(){}
  onKeyDown(){}
  onHover(){}
  onActive(){}
}
```

「`bind`するメソッドが多くて可読性が下がってしまう〜🥺」というときでしょうか
出来ることであればこの`bind`の処理だけでもループ処理させたいですよね😭


```js
const methods = [
    'onClick',
    'onChange',
    'onKeyUp',
    'onKeyDown',
    'onHover',
    'onActive',
];

for (const method of methods) {
    this[method] = this[method].bind(this);
}
```

でも毎回`constructor`で↑みたいなループ処理をコピペして使い回すのも億劫😢

という悩みから先程紹介した↓の関数を実装しました😮

```js
const binds = (methods, self) => {
    const result = {};
    for (const method of methods) {
        result[method] = self[method].bind(self);
    }
    return result;
};
```

使い方は至って簡単🤝

```js

const methods = [
    'onClick',
    'onChange',
    'onKeyUp',
    'onKeyDown',
    'onHover',
    'onActive',
];

class Hoge{
  constructor() {
    this.event = binds(methods, this);
  }

  onClick(){}
  onChange(){}
  onKeyUp(){}
  onKeyDown(){}
  onHover(){}
  onActive(){}
}

```

↑です✨

でも、クラス外で定義しただけじゃない？😅
このファイルの結局行数変わらないよね？😫
そんなこと無いですよ🥳

configファイルを作ってそのファイルで一括管理しましょう😆

```js
const methods = {
    src: {
        components: {
            "index.js": [
                'onClick',
                'onChange',
                'onKeyUp',
                'onKeyDown',
                'onHover',
                'onActive',
            ],
        },
    },
};
```

↑はプロジェクトのルートディレクトリをカレントパスとした場合の定義です。

`methods.src.components["index.js"]`で取り出すことは可能ですが、
合理的かつ動的に取り出せたほうが楽ですよね、、、🤭

```js
const arrayKey2Column = (targetArray, searchArray) => {
    for (const searchKey of searchArray) {
        if (targetArray[searchKey]) {
            targetArray = targetArray[searchKey];
            continue;
        }
        return false;
    }
    return targetArray;
};
```

↑書いてみました！

```js
const splitPath = ["src", "components", "index.js"];
const targetMethods = arrayKey2Column(methods,splitPath);
```

でも`["src", "components", "index.js"]`を動的に取得したいな🥺

```js
const splitPath = __filename.split("/");
const targetMethods = arrayKey2Column(methods,splitPath);
```

↑でその悩みも解決🤝

ということは、

```js
const getBinds = (filename) => {
    return arrayKey2Column(
        methods,
        filename.split("/")
    );
};
```

こういうヘルパー関数を用意しておけば、

```js
const targetMethods = getBinds(__filename);
```

で実装できそうですね！

## まとめ

ここまでのソースコードをまとめると↓のような実装になります👦

```js

// configファイルに定義
const methods = {
    src: {
        components: {
            "index.js": [
                'onClick',
                'onChange',
                'onKeyUp',
                'onKeyDown',
                'onHover',
                'onActive',
            ],
        },
    },
};

// helperファイルに定義
import { methods } from 'config';

const getBinds = (filename) => {
    return arrayKey2Column(
        methods,
        filename.split("/")
    );
};

const binds = (methods, self) => {
    const result = {};
    for (const method of methods) {
        result[method] = self[method].bind(self);
    }
    return result;
};

// 対象のコンポーネント
import { getBinds,binds } from 'helper';

const targetMethods = getBinds(__filename);

class Hoge{
  constructor() {
    this.event = binds(targetMethods, this);
    // this.event.onClick
    // ~
  }

  onClick(){}
  onChange(){}
  onKeyUp(){}
  onKeyDown(){}
  onHover(){}
  onActive(){}
}
```

メモ程度に記録しただけなので、
同じような機会があった時にこの記事を思い出してもらえれば嬉しいです！笑

ありがとうございました(๑╹ω╹๑ )