ikemonn's blog

技術ネタをちょこちょこと

【Underscore.js】_.reduceを読んだ

概要

リストの要素を一つの値にまとめていく。 引数のmemoは初期値。 iterateeが実行されたあと、その値をメモ化しておき、リストのindex番目の値とともにiterateeに渡し、各値を処理する。

var list = [1, 2, 3];
var sum = _.reduce(list, function(memo, num){
    return memo + num;
});
console.log(sum); // 6

ソースコード

 // Create a reducing function iterating left or right.
  function createReduce(dir) {
    // Optimized iterator function as using arguments.length
    // in the main function will deoptimize the, see #1991.
    function iterator(obj, iteratee, memo, keys, index, length) {
      for (; index >= 0 && index < length; index += dir) {
        var currentKey = keys ? keys[index] : index;
        memo = iteratee(memo, obj[currentKey], currentKey, obj);
      }
      return memo;
    }

    return function(obj, iteratee, memo, context) {
      iteratee = optimizeCb(iteratee, context, 4);
      var keys = !isArrayLike(obj) && _.keys(obj),
          length = (keys || obj).length,
          index = dir > 0 ? 0 : length - 1;
      // Determine the initial value if none is provided.
      if (arguments.length < 3) {
        memo = obj[keys ? keys[index] : index];
        index += dir;
      }
      return iterator(obj, iteratee, memo, keys, index, length);
    };
  }

  // **Reduce** builds up a single result from a list of values, aka `inject`,
  // or `foldl`.
  _.reduce = _.foldl = _.inject = createReduce(1);

createReduce()は、引数が4つの関数を返す。 その関数の中で実際の処理が行われていく。 関数を返すのが面白いと思った。

 参考

jashkenas/underscore