第二回。
まずはmap。
_.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 = _.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 = _.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右から縮めていくので実行環境によってしまいますし。