JavaScriptの高階関数

関数型プログラミングに非常に便利なJavaScriptの機能の1つは、高階関数を受け入れることができることです。 高階関数は、別の関数を引数として使用したり、結果として別の関数を返すことができる関数です。



ファーストクラスの機能


JavaScriptが関数をファーストクラスオブジェクトと呼ぶことを聞いたことがあるでしょう。 この式は、JavaScriptの関数がオブジェクトと同じステータスを持つことのみを意味します。オブジェクトのタイプはObjectです。 変数値として設定できます。 他の変数と同様に、参照によって受け渡しできます。



このネイティブプロパティは、関数型プログラミングでJavaScriptの特別な機能を提供します。 関数はオブジェクトであるため、この言語は関数型プログラミングへの自然なアプローチをサポートしています。 実際、このアプローチは非常に自然なので、おそらくあなたはそれを使用し、それについて考えなかったに違いない。



引数として関数を受け入れます


多くのWeb指向のJavascriptプログラミングまたはブラウザー開発を行った場合、おそらくコールバック関数( コールバック -約Translator)を使用する関数に出くわしました。 コールバック関数は、他のすべての操作が既に完了しているときに、操作の最後に実行される関数です。 通常、コールバック関数は、関数の最後の引数として渡されます。 多くの場合、コールバック関数は匿名関数として定義されます。



JavaScriptはシングルスレッドのプログラミング言語です。つまり、操作は順番に実行されるため、各操作は単一のストリームで受信するためにキューに入れられます。 他の親関数が完了したときに関数を実行に移す戦略は、高階関数をサポートするプログラミング言語の主な特徴の1つです。 そのため、非同期の動作を取得できます。つまり、スクリプトは結果を待っている間も実行を続けます。 コールバック関数を転送する機能は、無期限に結果を返す可能性のあるリソースを扱う場合に重要です。



このアプローチは、スクリプトがAjaxリクエストをサーバーに送信し、サーバーのネットワーク遅延と処理時間を考慮して、受信時間に関係なく応答を処理できるWeb開発環境で非常に便利です。 Node.jsは、サーバー容量を最も効率的に使用するためのコールバック関数を指すことがよくあります。 このアプローチは、機能が開始する前にアプリケーションがユーザー入力を待機している場合にも有効です。



たとえば、次の簡単なJavaScriptコードのスニペットに注意してください。このコードは、ボタンにイベントハンドラーを追加します。

<button id="clicker">So Clickable</button> <script> document.getElementById("clicker").addEventListener("click", function() { alert("you triggered " + this.id); }); </script>
      
      





このスクリプトは、匿名関数を使用して警告を表示します。 ただし、個別に定義された関数を使用して、この名前付き関数をaddEventListenerメソッドに渡すこともできます。

 var proveIt = function() { alert("you triggered " + this.id); }; document.getElementById("clicker").addEventListener("click", proveIt);
      
      





私たちがaddEventListener関数にproveItI()ではなくproveItを渡したことに注意してください。 括弧なしで名前で関数を渡す場合、関数にオブジェクトを渡します。 括弧で渡すと、関数の結果が渡されます。



私たちの小さなproveIt()関数は、それを取り巻くコードから構造的に独立しており、常にそれが機能した要素のidを返します。 この小さなコードは、要素のidを使用して警告を表示する任意のコンテキストに配置でき、イベントハンドラーから呼び出すこともできます。



個別に定義された関数を名前付き関数に置き換える機能は、可能性の全世界を開きます。 外部データを変更せず、毎回同じ入力で同じデータを返す純粋な関数を作成しようとすると、使用に適した小さなターゲット関数のライブラリを作成するのに役立つ重要なツールが得られますどのアプリケーションでも。



結果として関数を返します


JavaScriptは、関数を引数として受け入れることができることに加えて、関数が結果として他の関数を返すことを許可します。 関数は単なるオブジェクトであり、他の値と同様に返されるため、これは論理的です。



しかし、結果として関数を返すとはどういう意味ですか? 関数を別の関数の逆関数として定義する場合、新しい関数を作成するためのテンプレートとして使用できる関数を作成できます。 これにより、JavaScriptの機能魔法の世界への扉が開かれます。



たとえば、ミレニアル世代の機能について読むことにうんざりしているため、Webに表示されるたびに「ミレニアル」という単語を「ヘビの人々」というフレーズに置き換えることにしたとします。 通常、リクエストに応じて、あるテキストを別のテキストに置き換える関数を作成するだけです。

 var snakify = function(text) { return text.replace(/millenials/ig, "Snake People"); }; console.log(snakify("The Millenials are always up to something.")); // The Snake People are always up to something.
      
      





これは機能しますが、この特定の状況でのみです。 また、団塊の世代について聞いて疲れています。 あなたも彼らのためにカスタム関数を書きたいです。 唯一の問題は、そのような単純な関数であっても、すでに記述されたコードを繰り返したくないことです。

 var hippify = function(text) { return text.replace(/baby boomers/ig, "Aging Hippies"); }; console.log(hippify("The Baby Boomers just look the other way.")); // The Aging Hippies just look the other way.
      
      





ただし、アルゴリズムをコードに保存するためにより洗練された何かをすることにした場合はどうでしょうか? これを行うには、最初と2番目の機能の両方を変更する必要があります。 これは非常に面倒であり、コードをより脆弱で読みにくくします。



本当に必要なのはコードの柔軟性です。この機能では、用語を関数テンプレート内の他の用語に置き換え、他の多くの関数を作成できるメイン関数の動作を決定できます。



JavaScriptでは、値の代わりに関数を返す機能を使用して、タスクをより効率的に完了することができます。

 var attitude = function(original, replacement, source) { return function(source) { return source.replace(original, replacement); }; }; var snakify = attitude(/millenials/ig, "Snake People"); var hippify = attitude(/baby boomers/ig, "Aging Hippies"); console.log(snakify("The Millenials are always up to something.")); // The Snake People are always up to something. console.log(hippify("The Baby Boomers just look the other way.")); // The Aging Hippies just look the other way.
      
      







メインの作業を行うコードを、元のフレーズを使用して任意の行を変更するために必要なすべての作業をカプセル化し、特定の位置から置換するユニバーサルで拡張可能な機能に分離しました。



最初の2つの引数を受け取った姿勢関数への参照として新しい関数を定義すると、新しい関数は任意の引数を受け取り、姿勢関数によって返される内部関数のテキストソースとして使用できます。



したがって、JavaScript関数の機能を使用して、最初に設定された引数の数に依存せず、任意の数の引数を受け入れます。 引数が存在しない場合、関数は単にそれを未設定と見なします。



一方、この追加の引数は、上記で説明したように、要求された関数が指定されたときに、つまり、1つおよび多数の未定義の引数を持つ別の関数から返される関数への参照として渡すことができます。



高階関数がどのように機能するか理解していない場合は、テキストをもう一度確認してください。 別の関数を返す関数テンプレートを作成します。 次に、1つの属性を除いて、この新しく返された関数を、関数テンプレートのカスタム実装として定義します。 この方法で作成されたすべての関数は、関数テンプレートから同じコードを継承しますが、デフォルトでは異なる引数を受け取ることができます。



すでに高次関数を適用しています


高階関数はJavaScriptの中核であるため、既に使用しています。 匿名関数またはコールバック関数を渡す必要があるたびに、渡される関数によって返される値を操作し、別の関数の引数として使用します。



他の関数を返す関数の機能により、JavaScriptは非常に便利になり、ユビキタス関数テンプレートを使用して特定のタスクを実行するカスタム関数を作成できます。 これらの小さな関数はそれぞれ、関数テンプレートコードに表示されるすべての改善点を取得します。 これにより、コードの重複が回避され、コードがよりクリーンで読みやすくなります。



追加のボーナスとして:関数に副作用がないことを確認し、値を変更せず、データ入力に対して常に変更せずに返す場合、テストスイートを作成し、テンプレート関数のコードの変更を確認する絶好の機会がありますエラーにつながることはありません。



自分のプロジェクトでこのアプローチをどのように使用できるかを考えてください。 JavaScriptの利点は、既存のコードに新しい機能を追加できることです。 実験してみてください。 高階関数を使用した簡単な操作でコードを改善できることに驚くでしょう。



著者について


M.デビッドグリーン

Apple、Salon.com、StumbleUpon、Moovwebなどの企業のWeb開発者、ライター、コミュニケーションマネージャー、マーケティングディレクターとして働いていました。 カリフォルニア大学バークレー校で行っている私の研究「電気通信の社会学」と「組織行動」の分野でのビジネスの修士号は、人が自分の種とのコミュニケーションの本能によって駆動されていることを理解する十分な理由となりました。通信環境に関係なく、いつでもどこでも動作します。



翻訳作業: greebn9k (Sergey Gribnyak)、 silmarilion (Andrey Khakharev)

シングリー



All Articles