JavaScriptの高度な関数 - React Vernacular キャンペーン 04

Javascript 高階函式 -HigherOrderFunction

序文

この記事では、JavaScript関数の非常に重要な概念である高階関数を紹介する。

高階関数とは、1つ以上の関数をパラメータとして返す関数、または1つの関数を結果として返す関数のことである。

この記事では、高階関数とは何か、高階関数を使用するメリット、実際のアプリケーションでの使用方法について詳しく見ていきます。

  1. 機能の方向性は?
  2. 純粋機能
  3. 高次関数
  4. キュアリング

機能の方向性は?

いわゆる関数指向とは、一言で言えば、関数そのものが変数であるということだ。例えば、関数はconst、let、varを使って宣言することができ、引数にして他の関数に渡したり、配列やオブジェクトに追加したりすることができる。

関数を引用符として別の関数に渡す。

				
					const print = (message) => { console.log(`print function with ${message}`) } const helloMessage = () => { return "Hello Message" } print(helloMessage());こんにちはメッセージ
				
			

配列の追加

				
					const array = ["item0", (message) => console.log("私は配列の item 関数です " + message)] console.log(array[0]); // item0 array[1]("argument "); // 配列引数の item 関数です
				
			

オブジェクトの追加

				
					const object = { helloWorld: "Hello World", print: (message) => { console.log(`print function with ${message}`) } } object.print(object.helloWorld); // print 関数 with ${message}`世界
				
			

純粋機能

関数が引数によってのみ影響を受ける場合、それは純粋関数と呼ばれる。このような純粋関数は、他の変数に干渉されないので、このような関数は封印され、他の変数や引用符に干渉されない、つまり副作用がある。

いわゆる副作用とは、関数の実行中に起こる外部からの変化を指す。

  1. Date.now() あるいは Math.random() を使用する。
  2. console.log()を使う
  3. 外部情報の修正
  4. DOMの操作
  5. HTTPリクエストを出す

純粋な関数ではなく、外部データが変更されると影響を受ける次の例を見てみよう。

				
					y = 1; 関数 xAdd(x) { return x+y };
				
			

xAdd(5)を実行しても、yが変化するため結果が異なることがわかるだろう。

純粋関数の利点は、その独立性だけでなく、テストが書きやすいことです。

				
					関数 sum(x, y) { return x + y }; //3
				
			

高次関数

高階関数とは、「関数を受け入れるか、関数を返す」関数である。

アクセプタンスとは、関数を引数として入力することである。

コールバック関数は、関数を変数として返すもので、mapやreduceなどの高階関数にはいくつかの種類がある。

上記のファンクションガイドはその一例なので、おさらいしておこう。

				
					// 高階関数のパラメータとして渡されるコールバック関数 function callbackFunction(){ console.log('I am a callback function') } // 高階関数 function higherOrderFunction(func){ console.log('I am 高階関数') func() } highOrderFunction(callbackFunction);
				
			

上のコードでは、higherOrderFunction()はコールバック関数を引数として渡しているので、HOFである。

上記の例は十分シンプルなので、さらに一歩進めて、HOFを使ってよりクリーンでモジュール化されたコードを書く方法を見てみよう。

高階関数の仕組み

円の面積と直径を計算する関数を書きたいとする。プログラミングに慣れていないため、最初に思いつく解決策は、円の面積や直径を別々に計算する関数を書くことです。

				
					const radius = [1, 2, 3]; // 円の面積を計算する関数 const CalculateArea = function (radius) { const Output = [] for(let i = 0; i< radius.length; i++ ){ Output.push(Math.PI * radius[i] * radius[i]); } return Output; } // 円の直径を計算する関数 const CalculateDiameter = function (radius) { const Output = [] for (let i = 0; i< radius.length; i++){output.push(2 * radius[i]) } console.log(calculateArea(radius)); )
				
			

しかし、上記のコードに問題があることにお気づきだろうか?

ほぼ同じ関数を何度も書き直しているが、ロジックが微妙に違うし、書いている関数も何度も使えるものではないので、同じコードを書くために高階関数を使う方法を見てみよう:

				
					const radius = [1, 2, 3]; // 面積を計算するロジック const area = function(radius){ return Math.PI * radius * radius } // 直径を計算するロジック constdiameter = function(radius){ return; 2 * radius; } // 面積、直径などを計算するための再利用可能な関数 const Calculate = function(radius,logic){ const Output = []; for(let i = 0; i < radius.length; i++){ .push(logic(radius[i])) } 出力を返します。 } console.log(calculate(radius, area));
				
			

上のコードを見てわかるように、円の面積と直径を計算するための関数はcalculate()ひとつしか書いていない。あとはロジックを書いてcalculate()に渡すだけで、関数が仕事をしてくれる。

高水準関数を使って書くコードは簡潔でモジュール化されており、それぞれの関数がそれぞれの仕事をする。

将来、円の円周を計算するプログラムを書きたいとする。円周率を計算するロジックを書き、それをcalculate()関数に渡すだけでよい。

				
					const circumference = function(radius){ return 2 * Math.PI * radius } console.log(calculate(radius, circumference));
				
			

その他の反例やアロー関数の応用例もここで紹介する。

				
					const print = (message) => { console.log(`print function with ${message}`) } const helloMessage = () => { return "Hello Message" } print(helloMessage());こんにちはメッセージ
				
			

しかし、より高次の関数を使えば、より便利で複雑な状況を扱うことができる。

				
					const printNameByCondition = (condition, trueFunc, falseFunc) => { 条件 ? trueFunc() : falseFunc(); } const printHogan = () => console.log("Hello Hogan") => コンソール。 log("Hello BoBo"); printNameByCondition(true, printHogan, printBobo); // こんにちは、Hogan printNameByCondition(false, printHogan, printBobo);
				
			

ここにあるように、私は3つの引数を持つ関数を作った。

最初の引用文を通して、もしそれが真であれば、最初の関数が実行され、そうでなければ、2番目の関数が実行される。

高階関数の使い方

配列を扱う場合、map()、reduce()、filter()、sort()関数を使用して、配列内のデータを操作したり変換したりすることができます。

高度な関数処理オブジェクト

オブジェクトから新しいオブジェクトを作成するには、Object.entries()関数を使用します。

関数を使った高階関数

compose()関数を使えば、単純な関数から複雑な関数を作ることができる。

重要な高次関数の使い方

JavaScriptには、map()、filter()、reduce()といった代表的な高階関数が数多く組み込まれている。これらを詳しく見てみよう。

JavaScriptでのmap()の使い方

map() 関数は配列を受け取り、元の配列を変更せずに配列内の各値を変換します。この関数は、値の配列を別の構造の新しい配列に変換する際によく使用します。

事例 1仮に、配列の各要素に以下を追加したいとしよう。 10.私たちは map() メソッドは、配列の各要素を 10

				
					const arr = [1, 2, 3, 4, 5]; const 出力 = arr.map((num) => num += 10) // [1, 2, 3, 4, 5] console.log(出力) // [11, 12, 13, 14, 15]
				
			

上記の例では、arrは5つの要素からなる配列である:

mapメソッドを使って配列の各要素に関数を適用し、変更後の要素を含む新しい配列を送り返す。

マップに渡されるコールバック関数は、numをパラメーターとするアロー関数を使用する。

この関数は、num(配列の各要素)に10を足して結果を返す。

例2:ここにユーザーの配列がある。ユーザの名前だけが必要だとします。単に map() メソッドを使って、users 配列から取り出します。

				
					const users = [ {firstName: 'John', lastName: 'Doe', age: 25}, {firstName: 'Jane', lastName: 'Doe', age: 30}, {firstName: 'Jack', lastName: ' Doe', age: 35}, {firstName: 'Jill', lastName: 'Doe', age: 40}, {firstName: 'Joe', lastName: 'Doe', age: 45}, ] const result = ユーザー。 map((user) => user.firstName + ' ' + user.lastName) console.log(result); // ['ジョン ドゥ', 'ジェーン ドゥ', 'ジャック ドゥ', 'ジル ドゥ', 'ジョードー」]
				
			

上のコードでは、usersはユーザーを表すオブジェクトの配列である。各オブジェクトには、姓、名、年齢の3つの属性があります。

map() メソッドを使用して、各ユーザーをマップし、属性 firstName と lastName を取得します。

コールバック関数は、users配列の要素(オブジェクト)を表すパラメータuserを受け取る。

この関数は、ユーザの name 属性と lastName 属性を連結して結果を返します。

JavaScriptでのfilter()の使い方

filter()関数は配列を受け取り、特定の条件にマッチする値のみを含む新しい配列を返します。

また、元の配列を変更しないので、特定の条件に基づいて配列からデータセットを選択するためによく使われる。

例 1: filter() 関数を使用して、数値の配列から凡例を返します。

				
					const arr = [1, 2, 3, 4, 5]; const Output = arr.filter((num) => num % 2) // 奇数を除外します console.log(arr); // , 3, 4, 5] console.log(出力) // [1, 3, 5]
				
			

上記のコードでは、arrは5つの要素を持つ配列である:

フィルターは、指定されたコールバック関数で指定されたテストに合格しなければならない要素を持つ新しい配列を作成するためのメソッドです。

コールバック関数は、numが2で割り切れるかどうか(num % 2)をチェックすることによって、numが奇数かどうかをチェックします。num が2で割り切れない場合、関数は真を返し、そうでない場合は偽を返します。

arr で filter を使用すると、配列の各要素に関数が適用され、true を返すか指定した条件を満たす要素だけを含む新しい配列が作成されます。元の配列は変更されず、結果を返します。

例 2: filter() を使用して、30 歳以上のユーザーだけを配列に返すことができます。

				
					const users = [ {firstName: 'John', lastName: 'Doe', age: 25}, {firstName: 'Jane', lastName: 'Doe', age: 30}, {firstName: 'Jack', lastName: ' Doe', age: 35}, {firstName: 'Jill', lastName: 'Doe', age: 40}, {firstName: 'Joe', lastName: 'Doe', age: 45}, ] // ユーザーを検索します年齢が 30 歳を超える場合 const Output = users.filter(({age}) => age > 30) console.log(output) // [{firstName: 'Jack', lastName: 'Doe', age: 35} 、{名: 'Jill'、姓: 'Doe'、年齢: 40}、{名: 'Joe'、姓: 'Doe'、年齢: 45}]
				
			

上記のコードでは、usersはユーザーの配列である。各オブジェクトには、姓、名、年齢の3つの属性があります。

users 配列に対するフィルタと、配列の各要素に対するコールバック関数を使用します。

関数はパラメーターを取る。言い換えれば、1つのアトリビュート・エイジに再構築されたオブジェクトである。

この関数は、年齢が30歳以上かどうかをチェックする。そうであれば、この関数は真を返し、そうでなければピンバック false。

ユーザーに対してフィルタを使用すると、配列の各要素に対してこの関数が使用され、関数を渡した要素のみを含む新しい配列が作成されます。ピンバック 真でありピンバック結果元のユーザー配列は変更されていない。

結果元のユーザー配列は変更されていない。

多くの人にとってreduce()は比較的複雑な関数なので、以前にreduce()メソッドに遭遇したことがあり、最初に理解できなかった人は、この先を読んでください!

なぜreduce()を使うのか?すでに優れた関数はたくさんあるので、どの関数をいつ使うかをどうやって決めればいいのでしょうか?

reduce()の場合は、配列要素に対して演算を実行し、単一の値を返したい場合に使用する。

単一値:配列要素に関数を繰り返し適用した累積結果。

たとえば reduce() を使用して、配列のすべての要素を合計したり、 最大値や最小値を求めたり、複数のオブジェクトをひとつのオブジェクトにまとめたり、 配列のさまざまな要素を分割したりすることができます。いくつかの例を見てみましょう。

例 1: reduce() を使用して、配列の全要素の合計を求める:

				
					const数値 = [1, 2, 3, 4, 5]; const sum =数値.reduce((total, currentValue) => { return total + currentValue; }, 0) console.log(sum);
				
			

この例では、reduce() メソッドを配列で使用し、total と currentValue という 2 つのパラメータを持つコールバック関数を渡しています。

totalパラメータは、この関数が使われたときに返される値の合計であり、currentValueは、処理されている配列の現在の要素である。

reduce()の2番目のパラメータも初期値で、上の例では0であり、最初のスタックのtotalの初期値として使われる。

それぞれの重ね合わせにおいて、関数は現在の値を合計とピンバック合計数の新しい値。

次に reduce() メソッドは、配列のすべての要素が処理されるまで、返された値を次の反復の合計値として使用する。

最後に、配列の全要素の合計である合計値を返す。

例 2: reduce() を使用して列の最大値を求める:

				
					let 数値 = [5, 20, 100, 60, 1]; const maxValue =数値.reduce((max, curr) => { if(curr > max) max = curr; return max; }); maxValue); // 100
				
			

この例では、コールバック関数で再び max パラメータと curr パラメータを使用しますが、今回は reduce() メソッドで 2 番目のパラメータを渡しません。したがって、デフォルト値は配列の最初の要素となります。

コールバック関数は、まず現在の要素currが現在の最大値maxより大きいかどうかをチェックします。大きい場合は、maxの値を更新して現在の要素にします。そうでなければ、maxを更新せず、最後にmaxの値を返します。

この例では、 reduce() メソッドはまず max を 5 に、curr を 20 に設定し、次に 20 が 5 より大きいかどうかをチェックし、大きければ max を 20 に更新する。

次にcurrを100に設定し、100が20より大きいかどうかをチェックする。

この処理は、配列の全要素が処理されるまで続けられる。maxは最終的に配列の最大値となり、この場合は100となる。

高次関数の利点

高階関数を使うことは、開発者にとって重要な利点がある。

第一に、高階関数はコードをより簡潔で理解しやすくし、コードの読みやすさを向上させ、開発プロセスのスピードアップに役立ち、コードを使いやすくする。

第二に、高階関数はコードをまとめるのに役立ち、保守や拡張が容易になる。

キュアリング

カリーディングは、高階関数における特別で重要なテクニックである。

この概念を使うことで、高階関数から異なるレベルの引用符を渡したり、高階関数に接頭辞を追加したりすることができる。

				
					const userLogs = userName => message => console.log(`${userName} -> ${message}`) const log1 = userLogs("Hello World"); ; const log2 = userLogs("Hello World");
				
			

これも例を使って実装されており、高階関数には2つの異なる接頭辞が与えられる。

結語

この記事では、関数の方向性の概念、高階関数とは何か、高階関数を使用する利点、実際のアプリケーションで高階関数を使用する方法、そしてCurringが何をするのかについての比較的小さな紹介、Pure Functionsの紹介について説明します。

高階関数を使用することで、開発者はよりスマートにコードを書くことができ、コードをモジュール化し、より明確で使いやすくすることができる。

ご意見、ご質問がございましたら、お気軽にコメントをお寄せください!

この連載が気に入ったら、より多くの人に見てもらえるよう、遠慮なく「いいね!」やシェアをお願いします!

引用

リアクト・バーナキュラー・キャンペーン 05-高次機能

その他の参考記事

JavaScript非同期待ち - React Whitepaper キャンペーン03

JavaScriptのES6オブジェクト - Reactホワイトペーパーキャンペーン02

JavaScript ES6 - Reactホワイトペーパーキャンペーン01

Zustandとは? Reactフロントエンドの状態管理

ja日本語