JavaScriptの2つの柱-パート2:関数型プログラミング
Two Pillars Javascript Part2
JavaScriptは、その人気だけでなく、プログラミング開発にとって非常に重要な2つの機能を促進するため、これまでで最も重要なプログラミング言語の1つです。
プロトタイプの継承(クラスのないオブジェクト、プロトタイプデリゲート、OLOOとも呼ばれます-他のオブジェクトにリンクされたオブジェクト)、および
関数型プログラミング(クロージャ付きのラムダによって有効になります)
一般的に、私はこれらの例をJavaScriptの2つの柱と呼びたいと思います。彼らが私に影響を与えたことを認めるのは恥ずかしいことではありません。私はそれらのない言語でプログラムしたくありません。
関数型プログラミングは、再利用できるいくつかの機能を提供します。さまざまな実装で、さまざまな名前のさまざまなコレクションが使用されます。以下のリストは主にHaskellのドキュメントからのものです。 Haskellは人気のある関数型言語ですが、いくつかの人気のあるJavaScriptライブラリに同様の関数があります。
一般的なツールを一覧表示します。
- Head()-最初の要素を取得します
- Tail()-最初の要素を除くすべての要素を取得します
- Last()-最後の要素を取得します
- Length()-要素の数
述語/コンパレータ(テスト要素、ブール値を返す)
- 等しい()
- greatThan()
- 未満()
リスト変換:
- Map()([x])-> [y]-リストxを取得し、リスト内の各要素に変換を適用して、新しいリストyを返します。
- reverse()([1、2、3])-> [3、2、1]
リスト検索:
- Find()([x])-> x-リストxを取得し、一致する述語の最初の要素を返します
- Filter()([x])-> [y]-リストxを受け取り、一致する述語のすべての要素を返します
リストレデューサー/フォールド:
- Reduce()—([x]、function [、accumulator])-各要素に関数を適用し、結果を単一の値として累積します
- Any()-いずれかの値が述語に一致する場合はtrue
イテレータ/ジェネレータ/コレクタ(無制限のリスト)
- Sample()-連続入力ソースの現在の値(温度、テーブル入力、トグルスイッチのステータスなど)を返します。
- repeat()—(1)-> [1、1、1、1、1、1、…]
- Cycle()/ loop()-リストの最後に到達したら、最初に戻ります。
これらのユーティリティプログラムのいくつかは、ECMAScript5アレイに追加されました。
// Using ES6 syntax. () => means function () {} var foo = [1, 2, 3, 4, 5] var bar = foo.map( (n) => n + 1 ) // [2, 3, 4, 5, 6] var baz = bar.filter( (n) => n >=3 && n <=5) // [3,4,5] var bif = baz.reduce( (n, el) => n + el) // 12
汎用インターフェースのリストとして
上記の関数のほとんどは、リストを管理または導出するためのユーティリティであることに気付くかもしれません。多くの関数型プログラミングを開始すると、すべてをリスト、リスト要素、リスト値をテストするための述語、またはリスト値に基づく変換と考えるようになるかもしれません。このアイデアは、非常に再利用可能なコードの基礎を築きました。
ジェネリックは、さまざまな異なるデータ型を処理できる関数です。 JavaScriptでは、コレクションを操作する関数の多くは汎用です。たとえば、文字列は文字の配列として扱うことができるため、文字列と配列に同じ関数を使用できます。
単一のタイプにのみ適用可能な機能を、複数のタイプの機能に適用可能な機能に変更するプロセスは、プロモーションと呼ばれます。
提供するあらゆるタイプのデータを処理できるこれらすべての関数の鍵は、データがリストで処理され、リストが同じインターフェースを共有することです。
すべてのマイクロマネジメントを停止する方法
オブジェクト指向で命令型プログラミングでは、すべてを細かく管理します。状態を細かく管理し、カウンターを繰り返し、イベントエミッターやコールバックなどのイベントが発生する時刻を管理します。この作業はすべて完全に不要だと言ったら、プログラムからすべてのカテゴリのコードを削除できますか?
リアクティブプログラミングでは、map、filter、reduceなどの関数ユーティリティを使用して、システム全体に伝播するデータストリームを作成および処理します。 反応式 。 xを入力して変更すると、出力yが自動的に更新されて応答します。
OOでは、いくつかのオブジェクト(フォーム入力など)を設定し、オブジェクトをイベントエミッターに変換し、特定のリンクをスキップしてイベントをトリガーする可能性のあるイベントリスナーを設定できます。いくつかの出力を生成します。
リアクティブプログラミングを使用する場合は、より説明的な方法でデータの依存関係を指定します。手間のかかる作業のほとんどは標準機能ユーティリティにオフロードされるため、何度も何度も車輪の再発明を行う必要はありません。
各リストがストリームであると想像してください:配列は要素の順序での値のストリームです。フォーム入力は、変更されるたびにサンプリングされた値のストリームにすることができます。ボタンはクリックストリームです。
ストリームは、時間の経過とともに表現される単なるリストです。
用語であるRx(Reactive Extensions)では、監視可能なストリームを作成し、一連の機能ユーティリティ(上記)を使用してそれらを処理します。
特定のハッシュタグのすべてのソーシャルメディアフィードを表示したいとします。リストのリストを収集し、受け取った順序でマージしてから、上記のユーティリティ関数の任意の組み合わせを使用して処理できます。
これは次のようになります。
var messages = merge(twitter, fb, gplus, github) messages.map(normalize) // convert to single message format .filter(selectHashtag) // cherry pick messages that use the tag .pipe(process.stdout) // stream output to stdout
より良い非同期
あなたは約束について聞いたことがあるかもしれません。 promiseは、promiseの使用時に使用可能な値または使用できない値を処理するための標準インターフェイスを提供するオブジェクトです。言い換えれば、promiseには将来解決される可能性のある可能な値が含まれています。通常、関数呼び出しは、将来の値を解析できるPromiseを返します。
fetchFutureStockPrices().then(becomeAMillionaire)
.then()
株価が利用可能になったときにのみ呼び出されるため、正確にそのようにすることはできません。したがって、becomeAMillionaire
最終実行では、「将来の」株価が現在の株価になります。価格。
promiseは基本的に、単一の値(または拒否)のみを出力するストリームです。 Observableは、コード内のpromiseを置き換え、UnderscoreやLo-Dashなどのライブラリの使用に慣れている可能性のあるすべての標準機能ユーティリティを提供できます。
今こそ、関数型プログラミング、関数の純度、遅延評価などの利点を理解する良い機会です。今後数年以内にこれらのトピックについてもっと耳にすることをお約束します。