6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

underscore.jsを読む#2 map,reduce,reduceRight

Last updated at Posted at 2014-05-01

第二回。

まずはmap。

map.js
_.map = _.collect = function(obj, iterator, context) {
  var results = [];
  if (obj == null) return results;
  if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
  each(obj, function(value, index, list) {
    results.push(iterator.call(context, value, index, list));
  });
  return results;
};

nullが入った場合などの処理がありますが、eachでループしてpushしていくだけです。
次はreduce。

reduce.js
_.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;
};

inititalは初期値が存在するかを判定しています。初期値がなかった場合はlistの先頭の値を初期値としてeachによりループを回していきます。

ネイティブのreduceがあったときに少し特殊なことをしていて、contextをiteratorにbindしています。これはネイティブのreduceにそのような機能がないことによります。

最後はreduceRight

reduceRight.js
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
  var initial = arguments.length > 2;
  if (obj == null) obj = [];
  if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
    if (context) iterator = _.bind(iterator, context);
    return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
  }
  var length = obj.length;
  if (length !== +length) {
    var keys = _.keys(obj);
    length = keys.length;
  }
  each(obj, function(value, index, list) {
    index = keys ? keys[--length] : --length;
    if (!initial) {
      memo = obj[index];
      initial = true;
    } else {
      memo = iterator.call(context, memo, obj[index], index, list);
    }
  });
  if (!initial) throw new TypeError(reduceError);
  return memo;
};

reduceが「左」からなら、reduceRightは「右」から縮めていく関数です。配列が渡された場合はlengthを取得して1減らしながらeachでループを回していくだけになります。

オブジェクトがきた場合はlengthが定義できないので、まずkeyの配列を取得してそのlengthをとります。そして配列と同じように1減らしながらkeyからvalueを取得してループを回します。

eachで取得したvalueは完全に無視していますが、ループの回数は同じになるはずなので問題なしです。

reduce、reduceRightにオブジェクトを渡すのは使い所がよく分からないですね、、、for inの順番で左or右から縮めていくので実行環境によってしまいますし。

Annotated Sourceにも書いています

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?