機能的なJavaScriptでmapとreduceを使用する

マップの使用に関する翻訳資料に注意を向け、機能的なJavaScriptを削減します。 この記事は、主に初心者の開発者を対象としています。

新しい標準に関するこのすべての話では、今日のJavaScriptで関数型プログラミングを使用できるおかげで、多くのツールを提供してくれたのはECMAScript 5であることを忘れがちです。 たとえば、 Array JSオブジェクトに基づくネイティブmap()およびreduce()メソッド。 それでもmap()およびreduce()使用しない場合は、今が開始時です。 最新のJSプラットフォームのほとんどは、ECMAScript 5をネイティブでサポートしています。これらのメソッドを使用すると、コードがよりきれいになり、読みやすくなり、保守しやすくなります。 map()およびreduce()は、よりエレガントな機能開発パスに着手するのに役立ちます。

パフォーマンスノート


もちろん、状況によって必要とされる場合、コードの可読性と保守性がパフォーマンスを低下させることはありません。 最新のブラウザは、ループなど、よりかさばる従来のデザインをより効率的に実行します。

次の方法を試してください。まず、読みやすさと保守性の基準に基づいてコードを記述し、次に実際に必要な場合はパフォーマンスを最適化します。 時期尚早な最適化を避けます。

また、 map()reduce() map()などのメソッドを使用すると、ブラウザがその使用に最適化されるため、JSエンジンの改善点をさらに活用できることにも注意してください。 パフォーマンスに問題がない場合は、将来を楽観的な見方でコードを書くのが最善です。 そして、コードをすっきりさせるパフォーマンストリックは、必要なときに後で使用できるようにします。

地図を使用する


マッピングは、関数型プログラミングの基本的な手法です。 同じ長さの別の配列を作成するために、配列のすべての要素を操作するために使用されますが、変換されたコンテンツを使用します。

わかりやすくするために、簡単な例を見てみましょう。 単語の配列があり、元の配列内のすべての単語の長さを含む配列に変換する必要があるとします。 はい、これは最も関連性の高いケースではありませんが、このツールがどのように機能するかを理解することは、将来コードを改善するためにそれを適用するのに役立ちます。

おそらく、 forループを使用して説明したタスクを完了する方法を既にご存じでしょう。 たとえば、次のように:

 var animals = ["cat","dog","fish"]; var lengths = []; var item; var count; var loops = animals.length; for (count = 0; count < loops; count++){ item = animals[count]; lengths.push(item.length); } console.log(lengths); //[3, 3, 4] 

ここでいくつかの変数が定義されています:


次に、 animals配列の各要素を繰り返します。長さを計算し、 lengths配列に入れます。

注:このタスクは、要素変数と中間の割り当てなしで、 animals[count]の長さanimals[count]直接lengths配列に渡すことで、より簡潔に解決できます。 この単純な例でも、コードは少し短くなりますが、読みにくくなります。 同様に、パフォーマンスをわずかに改善するために、既知の長さのanimals配列を使用してlengths配列をnew Array(animals.length)として初期化し、 pushを使用push代わりにインデックスで要素を挿入します。 しかし、それはまた、コードを少しわかりにくくします。 一般的に、すべては実際のプロジェクトでコードをどのように使用するかに依存します。

技術的には、これが正しいアプローチです。 標準のJSエンジンで動作します。 しかし、 map()について学ぶとき、古典的な方法はすぐに面倒に見えます。

map()問題を解決する方法は次のとおりです。

 var animals = ["cat","dog","fish"]; var lengths = animals.map(function(animal) { return animal.length; }); console.log(lengths); //[3, 3, 4] 

ここで、 animals配列の変数から再び始めます。 しかし、それとは別に、 lengthsのみを宣言し、無名のインライン関数をanimals配列の各要素にマッピングすることで得られた結果を直接割り当てます。 無名関数は、各動物に対して操作を実行し、長さを返します。 最終的に、各単語の長さを含むlengths配列は、元のanimalsと同じ長さになります。

このアプローチでは次のことに注意してください。


このアプローチのもう1つの利点は、指定された関数を分離することにより、より柔軟にできることです。 これにより、コードがきれいになります。 匿名のインライン関数は、コードの再利用を困難にし、面倒に見える場合があります。 名前付きgetLength()関数をgetLength()て、次のように使用できます。

 var animals = ["cat","dog","fish"]; function getLength(word) { return word.length; } console.log(animals.map(getLength)); //[3, 3, 4] 

コードがどれほどきれいになり始めたかをご覧ください。 マッピングの適用を開始するだけで、すぐに新しいレベルの関数型プログラミングに到達できます。

ファンクターとは何ですか?


不思議なことに、配列オブジェクトにマッピングを追加すると、ECMAScript 5はメイン配列タイプを完全なファンクターに変えます。 これにより、関数型プログラミングがさらに手頃になります。

関数型プログラミングの古典的な定義によれば、ファンクターは3つの基準を満たします。

  1. 値のセットが含まれます。
  2. 各要素を操作するmap関数を実装しmap
  3. map関数は、同じサイズのファンクターを返します。

ファンクターについて詳しく知りたい場合は Matthias Peter Johanssonのビデオをご覧ください。

使用する


reduce()メソッドはECMAScript 5で初めて登場しました。map map()似ていmap()が、別のファンクターを作成する代わりに、 reduce()は単一の結果を生成します。 たとえば、 animals配列内のすべての単語の長さの合計を数値として取得する必要があります。 おそらく次のようにすぐに書きます。

 var animals = ["cat","dog","fish"]; var total = 0; var item; for (var count = 0, loops = animals.length; count < loops; count++){ item = animals[count]; total += item.length; } console.log(total); //10 

初期配列を記述した後、変数totalを作成して金額を計算し、ゼロを割り当てます。 また、変数item作成します。この変数には、forループが実行されるときに、 animals配列の各反復の結果が格納されます。 変数countループカウンターとして使用され、ループは反復を最適化するために使用されます。 forループを開始し、 animals配列内のすべての単語を繰り返し、それぞれの値をitem変数に割り当て、単語の長さを累積合計に追加します。

繰り返しますが、技術的には、ここですべてが正常です。 配列を処理し、結果を得ました。 ただし、 reduce()メソッドを使用すると、これがはるかに簡単になります。

 var animals = ["cat","dog","fish"]; var total = animals.reduce(function(sum, word) { return sum + word.length; }, 0); console.log(total); 

ここでは、新しい変数totalを定義し、匿名インライン関数と累積合計という2つのパラメーターを使用して、 animals配列にreduceを適用した後に得られた結果の値を割り当てます。 reduceは配列の各要素を取り、それに関数を適用し、結果をプログレッシブ合計に追加し、次の反復に渡します。 置換された関数は、2つのパラメーターを受け取ります。現在の合計と、配列から処理される現在の単語です。 この関数は、現在のtotal値をこの単語の長さに追加します。

reduce() 2番目の引数を無効にするため、 totalは数値であることに注意してください。 reduce()メソッドは2番目の引数がなくても機能しますが、結果は予期したものと異なる場合があります。 totalするときにJavaScriptが使用するロジックの種類を自分で決定してみてください。

おそらく、説明したアプローチは複雑すぎるようです。 これは、呼び出されたreduce()メソッドのインライン関数の統合定義の結果です。 無名インラインの代わりに名前付き関数を定義しましょう:

 var animals = ["cat","dog","fish"]; var addLength = function(sum, word) { return sum + word.length; }; var total = animals.reduce(addLength, 0); console.log(total); 

少し長くなりますが、これは必ずしも欠点ではありません。 この場合、 reduce()メソッドがどうなるかがより明確になります。 配列の各要素に適用される関数と、累積合計の初期値の2つのパラメーターを受け取ります。 この場合、新しい関数addLengthに累積合計の初期値(ゼロ)を渡します。 addLength()関数は、2つのパラメーターaddLength()積算合計と文字列値addLength()も取ります。

おわりに


map()reduce()定期的に使用することに慣れているため、コードをよりクリーンで、柔軟性があり、保守しやすくすることができます。 これにより、JavaScriptで他の機能的アプローチを使用する道が開かれます。

map()およびreduce()に加えて、他の新しいメソッドがECMAScript 5に登場しました。 一時的なパフォーマンスの低下は、コードの品質の向上と、開発の楽しさをはるかに上回ります。 アプリケーションでmap()reduce()が必要かどうかを気にする代わりに、機能的なアプローチを使用して、実際のプロジェクトのパフォーマンスへの影響を測定します。

Source: https://habr.com/ru/post/J324342/


All Articles