JavaScript

【JS】JavaScriptのバッククォートとカリー化の相性良すぎ問題

こんにちは!今日はJavaScriptのデザインパターンの一つ、バッククォート+カリー化について紹介します。

関数がめっちゃ綺麗になるぞ…!

結論

こういう書き方ができます

const greet = type => person => name => 
    `${type[0]}! ${person[0]} name is ${name[0]}.`

~greet `Hello` `My` `Mike`
// Hello! My name is Mike.

バッククォートの関数呼び出し

すごい簡単に言うと、関数をこんなかんじ()じゃなくてこんなかんじ``に呼び出せるってことです↓

const hello1 = name => `I'm ${name} .`
const hello2 = name => `I'm ${name[0]} .`

hello1('Mike') // I'm Mike.
hello2`Mike`   // I'm Mike.

こちらの記事で色々書いてるわ。

カリー化

カリー化はあれだ、詳しくはwikipedia見てもらうとして

要はn個の引数をとる関数を1個の引数をとるn個の関数にバラす感じ。こんな風に。

const sum1 = (n, m) => n + m
const sum2 = n => m => n + m

sum1(10, 32) // 42
sum2(10)(32) // 42

バッククォートとカリー化を合体させてみよう

3つの引数をとる関数【greet】を想定します。それぞれ、【挨拶】【人称】【名前】をとって、【こんにちは】!【僕】の名前は【マイク】です! みたいな文章を作ります。

普通に書く

普通に書くとこう。

const greet = (type, person, name) =>
  `${type}! ${person} name is ${name}.`

~greet('Hello', 'My', 'Mike')
// Hello! My name is Mike.

まあ全然読める。綺麗。ちなみにチルダ(~)はおまじないみたいなもんです。戻り値使わない関数には付けておこう。!や;でもいいよ。

バッククォートにしてみる…?

バッククォートにしてみたいけどバッククォートの関数呼び出しは引数1つしかとれんので一旦保留。

カリー化してみる

カリー化なら簡単。こう。

const greet = type => person => name =>
  `${type}! ${person} name is ${name}.`

~greet('Hello')('My')('Mike')
// Hello! My name is Mike.

うーん綺麗になったかは微妙なところ?関数側は綺麗になったけど、呼び出し側は冗長に見えます。

バッククォート+カリー化

本題。どうぞ

const greet = type => person => name => 
    `${type[0]}! ${person[0]} name is ${name[0]}.`

~greet `Hello` `My` `Mike`
// Hello! My name is Mike.

えっやばい…呼び出し側がめっちゃ綺麗。関数側汚くなってるけどな

まだ驚くことなかれ、これちょっと適当にインデントして、他の例も書いてみると…

const greet =

  type =>
  person =>
  name =>

  `${type[0]}! ${person[0]} name is ${name[0]}.`

~greet

  `Hello`
  `My`
  `Mike`
  // Hello! My name is Mike.

~greet

  `Hi`
  `Our`
  `Team Mike`
  // Hi! Our name is Team Mike.

もはやJSではない。いやこれが真のJSか。別言語。もう別言語。 さすがにここまでインデントするのはやりすぎだけど、新世界が見えた。

実用例

【.このclass】を【クリック】したら【このメッセージ出す】みたいな処理考える。

const greet = name => event => greet =>
  document.querySelectorAll(name[0]).forEach(e =>
    e.addEventListener(event[0], _=>
      alert(greet[0])
    )
  )

~greet
  `.greet-button`
  `click`
  `こんにちは!クリックしてくれてありがとう!`

~greet
  `.greet-area`
  `onmouseover`
  `こんにちは!ここは挨拶エリア`

~greet
  `.confirm`
  `click`
  `本当によろしいですか?`

呼び出し側がシンプルすぎる。関数側はカオス。

ライブラリとかに使えそう?

さいごに

バッククォート+カリー化、特に呼び出し側はめっちゃ綺麗になる。一方で関数はカオスになる。

ライブラリとか共通の関数みたいな、処理がブラックボックス化できるケースでやるとよさそう。

あと例のごとくIEは全く駄目だ

以上!