こんにちは!初めまして。エンジニアのTYです。
この度、初めてのブログ執筆と言うことで、僕が好きなJS関連のことを共有したいと思いました!
そこで、最近興味のある、JavascriptによるFunctional Programming(関数型プログラミング)をアウトプットも含め、知識をシェアしたいと思います。
Functional Programmingとは
「そもそもFunctional Programmingって何?」と思われた方も多いかと思います。もしかすると、「Object Oritented Programming(オブジェクト指向)は聞いたことある、もしくは、理解している。」方もいるかと思います。
Functional Programming(以下、FP)とは、プログラミングパラダイム(プログラミングの考え方と記述方法の枠組みを規定するもの)の一つです。
Javascriptといえば、Object Oriented Programming(以下、OOP)が有名だと思いますが、OOPもプログラミングパラダイムの一つです。ただ、オブジェクトを中心にプログラムを書くOOPとは違い、FPでは名前の通り、関数が中心になってきます。
少し具体的に言うと、
Pure Function(純粋関数)でソフトウェアを構成し、Shared State(グローバルスコープ、またはクロージャースコープにある変数)、Mutable Data(ミュータブルデータ)、Side-effects(副作用)を避けてプログラムすること。
FPにおいて、絶対に覚えておかなければいけないことは、
・Functions are pure(関数が純粋であること。)
・Variables are Immutable(変数はイミュータブルであること。)
文章による説明だと、「、、、 どう言うこと?」ってなるので、実際に手を動かしながら勉強していきたいと思います!
Functional Programmingの必須知識
FPを書く上で、必要な知識、実装の仕方があります。ここでは実際に手を動かしながら解説していきます。
Pure Functions(純粋関数)
FPにおいて関数がPure Functionsであることが前提となってきます。
Pure Functionsとは、
・同じ引数の場合、戻り値はいつも同じになる。
・副作用が発生しない。(データベース、ファイルの書き換え等々)
関数です。
Pure FunctionとImpure Function(Pure Functionではない関数)を書いてみると、
Impure Function
Pure Functionsの条件は
・同じ引数の場合、戻り値はいつも同じになる。
・副作用が発生しない。(データベース、ファイルの書き換え等々)
でした。
Impure Functionの例では、グローバルスコープの impureCar オブジェクトに依存しているため、副作用が発生しています。(値を直接変えている)
一方、Pure Functionの場合直接 pureCar オブジェクトには触れておらず、引数として受けとり、それをコピーして新たなオブジェクトを生成しています。(値はそのまま)
このように、FPでは、副作用をうまないPure Functionsを組み合わせてプログラムしていきます。
Immutability
immutableとは日本語で「不変」と言う意味で、FPにおいて一度定義したデータは変えません。
ただ、実際にデータを変えたい時はどうすればいいのか。ここでは、オブジェクト、配列のデータの変え方を見ていきます。
オブジェクトのデータ変更
どちらも直接もとのデータを変更していません。
また、配列を操作するときに直接配列を操作するpush, pop, shift, unshiftなどは使われません。
代わりにmap, filter, reduceがよく用いられます。
Currying (カリー化)
カリー化とは、簡単に表すと、関数に渡した引数が足りない場合、それを補う関数を返すこと指します。
わかりすく表記で表すと、f(a, b, c) を f(a)(b)(c) にすることです。
例えば、「引数を二つ取りたいけど、一つしか渡せない」ときは、f(a, b) を f(a)(b) の形にします。
例にあるgreet関数はgreetingとnameの引数が必要です。しかし、配列のmap関数で引数に渡せるのはnameだけなので、greet(greeting, name) から greet(greeting)(name) に変更する必要があります。
最終的にmap関数に渡されてる関数はgreet("hello")(name)となります。
Higher Order Functions(高階関数)
高階関数とは関数を引数としてとる関数、もしくは引数を返す関数を指します。
FPでは高階関数が至る所で使われ、実際に先程のカリー化の例でも使われています。
Functional Composition(関数合成)
関数合成とは他の関数と組み合わせて新しい関数を作ることです。
例えば、文字列の並びを反対にしたい場合2つの関数を用いて実行できます。
const split = (str) => str.split(" ");
const reverse = (arr) => arr.reverse().join("");
関数合成で一つにまとめると、
spritとreverseを組み合わせて、reverseStringと言う新たな関数を作っています。
reverseStringに渡した引数はsplitの引数として渡され、その戻り値がreverseの引数として渡されます。reverseの戻り値が最終的にreverseStringの戻り値となります。
R.composeの関数は、Ramdaと言うlibraryからインポートしています。
実はRamdaのように、FPのlibraryも数多く存在します。それらを用いることで、開発がしやすくなります。
Functional Programmingのメリット
ここまで記述方法を勉強しましたが正直、「書き方が決められていてめんどくさい、わかりにくい。」って思うますよね。なので最後にFPのメリットを紹介します。
・戻り値が決まっているので、テストがしやすい
・イミュータブルなので、バグがへる
・関数の使い回しができる(リユーザブル)
・関数の組み合わせがしやすい(コンポーザブル)
・キャッシュがしやすい
関数はPure Functions、変数はImmutableにするメリットはたくさんあります。
関数を書くときに、副作用がないに越したことはないですね。バグが生まれにくくなります。関数を組み合わせたり、使いまわすことも出来ます。また、同じ引数の場合、戻り値も同じになるので、テストがしやすくなります。
まとめ
以上、JavascriptでFunctional Programmingのコアな部分を解説しましたが、
OOPとFPはどっちが良いというものは無く、何を開発するのかによって使い分ける必要がありそうです。
僕自身、まだ表面的な部分しか学べておらず、勉強するたびに奥の深さを感じます。
この記事が勉強の役に立てれば幸いです。
ありがとうございました。
参考文献、資料、素材
- https://www.freecodecamp.org/news/what-is-a-pure-function-in-javascript-acb887375dfe/
- https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976
- https://dev.to/mpodlasin/functional-programming-in-js-part-ii-immutability-vanilla-js-immutable-js-and-immer-2ccm
- https://blog.bitsrc.io/functional-programming-in-javascript-how-and-why-94e7a97343b
- https://javascript.info/currying-partials
Udemyを実際に体験した方の感想記事もぜひご覧ください♪