ECMAScript 6 で導入される素晴らしい新機能をサポートするワークフローについての話題が多いため、ECMAScript 5 では JavaScript での関数型プログラミングをサポートする優れたツールとメソッドが提供され、それらを使用できるようになったということを忘れがちです。これらの関数メソッドのうち主なものは、JavaScript 配列オブジェクトに基づく map() メソッドとreduce() メソッドです。
まだmap()メソッドとreduce()メソッドを使用していない場合は、今すぐ使用を開始してください。現在の JavaScript 開発プラットフォームのほとんどは、ECMAScript5 をネイティブにサポートしています。 Map メソッドとreduce メソッドを使用すると、コードがより簡潔になり、読みやすく、保守しやすくなり、よりシンプルな機能開発への道を進むことができます。
もちろん、現実の世界がパフォーマンスの向上を要求する場合、コードの可読性と保守性のバランスが取れている必要があります。現在のブラウザでは、より効率的に実行するために、for ループなどのより面倒な従来の手法が使用されています。
私のコードの書き方は、通常、読みやすさと保守性を第一に考えてコードを書き、実際の状況で実行するコードに問題があることがわかった場合は、コードを最適化してパフォーマンスを向上させます。コードを早期に最適化することは困難であり、この最適化により、後でコードを記述することが困難になります。
将来的にブラウザーがパフォーマンスを向上させるために最適化を行うことを期待するのではなく、JavaScript エンジンで map() や Reduce() などのメソッドを使用することでコードのパフォーマンスを向上させることができることを考慮する価値があります。パフォーマンスの壁にぶつからない限り、私はコードを楽しく書くことを好みますが、たとえそうすることでコードの魅力が薄れるとしても、必要に応じてコードのパフォーマンスを維持するために常に調整する用意があります。
Map は、配列内のすべての要素に作用し、同じ長さと変換された内容を持つ他の配列を作成する基本的な関数プログラミング手法です。
今言ったことをより具体的にするために、簡単な使用例を考えてみました。たとえば、文字データを含む配列があり、それを各文字データの長さを含む別の配列に変換する必要があるとします。 (わかっています、これはロケット科学のように複雑ではありません。複雑なアプリケーションを作成するときに頻繁に実行しなければならないことですが、このような単純な例でそれがどのように機能するかを理解すると、それを使用するのに役立ちます。この場合、実際のデータ値をコード内に追加します)。
先ほど説明したように、配列で 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という名前の空の配列です。データ出力のデータと、ループが配列を横断するたびに操作する必要がある配列項目を一時的に格納するために使用される item と呼ばれる変数です。 for ループを定義します。これには内部変数と for ループを初期化するためのループ変数があります。次に、反復配列の長さが動物の配列の長さと等しくなるまで、各項目をループします。ループを通過するたびに、反復項目の文字長を計算し、長さ配列に保存します。
注: 議論する必要があるのは、item 変数を使用せずに上記のコードをより簡潔に記述し、animals[count] の長さを length 配列に直接入力できるため、中間変換が必要ないことです。プロセス 。これを行うと、コード領域を少し節約できますが、この非常に単純な例であっても、コードが少し読みにくくなります。同様に、コードをより効率的かつ単純なものにするために、push メソッドを使用してオプション データ長を挿入する代わりに、animals 配列の既知の長さを使用して new Array(animals.length) を介して長さ配列を初期化し、それにインデックスを付けることもできます。実際にコードをどのように使用するかによって異なります。
この実装には技術的なエラーはありません。これは標準的な JavaScript エンジンで動作し、問題なく作業を完了します。 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配列と同じ長さの配列になり、この配列には各文字の長さが含まれます。
这种方式需要注意的一些事情。首先,它比最初编写的代码更简洁。其次,我们仅需要申明更少的变量。更少的变量意味着在全局命名空间里杂音更少,并且如果相同代码的其他部分使用了相同的变量名就会减少碰撞的机会。最后,我们的变量不可能从头到脚都会改变它们的值。随着你深入函数式编程,你将会欣赏使用常量和不变的变量的优雅的能力,现在开始使用并不算早。
这种实现方式的另一个优点是,我们可以通过在整个代码编写过程中通过将代码放进一个个命名的函数里而简化代码而有机会提升自己编写代码的多功能性。匿名的内联函数看着有些乱,并且使得重复使用代码更困难。我们可以定义一个命名为getLength()的函数,并且像下面的方式来使用:
var animals = ["cat","dog","fish"]; function getLength(word) { return word.length; } console.log(animals.map(getLength)); //[3, 3, 4]
看看上面的代码看上去多简洁啊?只是把你处理数据的部分映射一下就使你的代码达到一个全新的功能水平。
有趣的一点是,通过在数组对象里添加映射,ECMAScript5把基本的数组类型变成了一个完整的函子,这使得函数式编程对我们来说更加的容易。
根据传统的函数编程定义,一个函子需要满足三个条件:
1.它保存着一组值。
2.它实现了一个map函数来操作每一个元素。
3.它的map函数返回一个具有同样大小的函子。
这个将会在你下一次的JavaScript聚会上被翻来覆去的讨论。
如果你想了解更多关于函子的信息,你可以看看Mattias Petter Johansson录制的关于这方面的视频。
Reduce()方法在ECMAScript5里也是新增的,而且它和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变量,并把它的初始值设为0。我们也定义一个变量item来保存每一次for循环迭代animals数组的迭代值,并且再定义一个count变量作为一个循环计数器,并且用这两个变量来初始化我们的迭代。然后我们运行for循环来迭代animals数组里的所有字符数据,每次迭代都会把迭代的结果保存到item变量。最终我们把每一次迭代到的item的长度加到我们的total变量里就可以了。
这种实现方式也没有任何的技术错误。我们从定义一个数组开始,然后得到一个结果值就结束了。但是如果我们使用了reduce()方法,我们可以使上面的代码更加简单明了:
var animals = ["cat","dog","fish"]; var total = animals.reduce(function(sum, word) { return sum + word.length; }, 0); console.log(total);
这里发生变化的是,我们定义了一个名为total的新变量,并且把执行animals数组对象的reduce方法的返回值分配给它,在reduce方法里有两个参数:一个匿名内联function方法,和初始化total的值为0。对于数组中的每一个项reduce()方法都会执行,它在数组的那一项上执行这个function函数,并且把它添加到运行总计,然后再进行下一次迭代。这里我们的内联function方法有两个参数:运行总计,和当前程序正在处理的从数组中获取的字符。这个function函数把当前total的值添加到当前word的长度上。
注意的是:我们设置reduce()方法的第二个参数值为0,这样做确定了total变量包含的是一个数值。如果没有第二个参数reduce方法仍然可以执行,但是执行的结果将不是你期望的那样。(你可以试试并且可以看看当运行总计结束后你是否能推测出JavaScript所使用的编程逻辑。)
那看上去似乎比它需要做的更有一点复杂,因为当调用reduce()方法时需要在一个内联function里综合的定义。我们再那么做一次,但是首先让我们定义一个命名的function函数,而不再使用匿名内联函数:
var animals = ["cat","dog","fish"]; var addLength = function(sum, word) { return sum + word.length; }; var total = animals.reduce(addLength, 0); console.log(total);
这个代码稍微有点长,但是代码有点长并不总是坏事。这样写你应该看到它使代码更加清晰些,只是在reduce()方法里发生了一点变化。
该程序里reduce()方法有两个参数:一个function函数,用来调用数组里的每一个元素,和一个为total变量设置的运行总计初始值。在这个代码示例中,我们放入了一个名为addLength的新function和为运行总计变量赋初始值为0。在上一行代码中,我们定义了一个名为addLength的function函数,这个函数也需要两个参数:一个当前和一个要处理的字符串。
map() メソッドとreduce() メソッドを頻繁に使用すると、コードをより簡潔に、より多用途に、より保守しやすくするためのオプションが提供されます。また、より機能的な JavaScript テクニックを使用するための道も開かれます。
map() メソッドとreduce() メソッドは、ECMAScript5 に追加された新しいメソッドの 2 つにすぎません。これらを今日使用すると、コードの品質と開発者の満足度の向上が、パフォーマンスへの一時的な影響を上回ることがわかるでしょう。 map() メソッドとreduce() メソッドがアプリケーションに適しているかどうかを判断する前に、実際に関数型関数技術を使用して開発し、実際の世界でその影響を測定してから、使用するかどうかを判断してください。
以上がJavaScript 関数プログラミングでの Map メソッドと Reduce メソッドの使用方法の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。