UnderScore.js の _.reduceメソッドに焦点をあてて勉強してみる
この記事は、タイトルどおり UnderScore.jsの _.reduceメソッドにカーソルをあてて書いている記事です。
ターゲットとしては、 Underscore.js reduce などで検索して訪問された方を対象にしています。
記事の書く流れ
1. _.reduceメソッドの使い方と概要
てっとり早く使い方を知りたいという方は、ここを読んでください。
2. 内部でどのように動いているか詳細を説明
内部の動きを知ることによって、reduceメソッドの仕様を説明していきます。
ご興味のある方は、どうぞ。
UnderScore.jsについて
JavaScriptのライブラリの一つで、これをインポートすると
_ オブジェクトがグローバル変数に設定されて,その _ オブジェクト内に
便利関数が80ほど定義されている。
公式サイト
http://underscorejs.org/
UnderScore.js ダウンロード先
http://underscorejs.org/underscore.js
//インポート例 <script type="text/javascript" src="http://underscorejs.org/underscore.js"></script>
_.reduceメソッドの使い方と概要
基本的な使い方は、配列の要素を1個ずつ取り出して まとめたいという時に使います。
では、配列を1個ずつ取り出して、一つの文字列にする使い方を書いてみますね。
var array = ["a", "b", "c"]; var iterator = function(sum, element){ sum += element; return sum; } var result = _.reduce(array, iterator); console.log(result); //=> "abc"
上記のように _.reduceメソッドを使って 配列要素を一つの文字列に出来ます。
使い方ですがまず、reduceメソッドの引数について説明します。
_.reduce( list, iterator, [memo], [context])
list | 処理したい配列やオブジェクト |
---|---|
iterator | 配列要素、個々の処理を担当する関数 |
memo | 省略可 まとめる時の初期値 |
context | 省略可 iterator関数内のthisに設定するオブジェクト |
iterator関数の引数は下記になります。
iterator( sum, element, [index], [list])
sum | 累積変数 まとめ先の変数 |
---|---|
element | 配列を1個ずつ取り出した値 |
index | 省略可 処理中の配列要素番号やkey名 |
list | 省略可 処理中の配列やオブジェクト |
なお iterator関数は、処理結果の値を返す必要があります。。
なんとなくイメージはお分かりになれましたでしょうか?
もう一つサンプルと memo まとめる時の初期値を 省略した場合の注意点を書いて 概要の説明は終わります。
var array = [1, 2, 3]; var result = _.reduce(array, function(result, value){result +=value; return result;}); console.log(result); //=> 6 var array = [1, 2, "3"]; var result2 = _.reduce(array, function(result, value){result +=value; return result;}); console.log(result2); //=> 33
1個目は、配列内の数値を合計する使い方です。
2個目は、同じように処理されていますが途中 文字列が含まれています。
その場合 (1+2)+"3" = 33 となることにご注意ください。
memo まとめる時の初期値を省略した場合は、 配列やオブジェクトの一番最初の要素が初期値になります。
内部でどのように動いているか詳細を説明
まず、UnderScore.js内で、reduceメソッドを定義している部分をはりつけます。
var reduceError = 'Reduce of empty array with no initial value'; // **Reduce** builds up a single result from a list of values, aka `inject`, // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { var initial = arguments.length > 2; if (obj == null) obj = []; if (nativeReduce && obj.reduce === nativeReduce) { if (context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); } each(obj, function(value, index, list) { if (!initial) { memo = value; initial = true; } else { memo = iterator.call(context, memo, value, index, list); } }); if (!initial) throw new TypeError(reduceError); return memo; };
まず結論から先にいうと
渡されたlist が 配列の場合で
Array.prototype.reduce - JavaScript | MDN
Array.prototype.reduceメソッドに対応しているブラウザであればその関数を使う。
Array.prototype.reduceメソッドに対応していないブラウザの場合は
Array.forEach - JavaScript | MDN
Array.prototype.forEachメソッドを使う。
Array.prototype.forEachメソッドに対応していない
or
配列以外の場合は
UnderScore.jsで独自に定義されている 処理を使う。
かんたんにいうと・・・。
nativeメソッドに対応していれば、nativeメソッドを使い
対応していなければ、独自に定義した関数を使う。
記事が長くなるので、次記事でコードの説明をしてみようと思います。