バージョン: 1.8.3
参考文献: http://underscorejs.org/docs/underscore.html
読んだ感想
- 前処理、実処理、後処理と分かれていて読みやすい
- 1メソッドが短くて読みやすい
_.each(obj, iteratee, context)
- サマリ
- 別名を
_.each = _.forEach
で定義 - 配列かそれ以外かで処理分岐
- 別名を
// 別名として、`_.forEach` も定義
_.each = _.forEach = function(obj, iteratee, context) {
// TODO: `optimizeCb` のリーディング
iteratee = optimizeCb(iteratee, context);
var i, length;
// 配列の場合
if (isArrayLike(obj)) {
// 配列長ループ
for (i = 0, length = obj.length; i < length; i++) {
// 第2引数として渡される関数を第1引数の各要素を引数として呼び出し
iteratee(obj[i], i, obj);
}
// 配列でない場合
} else {
// 対象オブジェクトのプロパティ名を取得
var keys = _.keys(obj);
// プロパティ数分ループ
for (i = 0, length = keys.length; i < length; i++) {
// `iteratee` 呼び出し
iteratee(obj[keys[i]], keys[i], obj);
}
}
// `_.each` 対象オブジェクトをそのまま返す
return obj;
};
_.map(obj, iteratee, context)
- サマリ
-
obj
が「配列」か「それ以外のオブジェクト」かで軽く分岐
-
// 別名`_.collect` も定義
_.map = _.collect = function(obj, iteratee, context) {
// `iteratee`のコンテキスト(`this`)設定
iteratee = cb(iteratee, context);
// オブジェクトのキー取得
var keys = !isArrayLike(obj) && _.keys(obj),
// オブジェクト長を取得
length = (keys || obj).length,
// 結果代入変数の初期化
results = Array(length);
// オブジェクト長分ループ
for (var index = 0; index < length; index++) {
// 結果の代入先が「プロパティ名」か「添え字」かを決定
var currentKey = keys ? keys[index] : index;
// `iteratee` を適用し結果を代入
results[index] = iteratee(obj[currentKey], currentKey, obj);
}
// 結果返す
return results;
};
_.reduce()
_.reduceRight()
_.find(obj, predicate, context)
- サマリ
- 実態は
_findIndex
と_.findKey
- 「配列」か「それ以外」かで分岐
- 実態は
// `_.detect` として別名定義
_.find = _.detect = function(obj, predicate, context) {
var key;
if (isArrayLike(obj)) {
key = _.findIndex(obj, predicate, context);
} else {
key = _.findKey(obj, predicate, context);
}
// `predicate` な値が存在する場合、その値を返す
if (key !== void 0 && key !== -1) return obj[key];
};
_.filter(obj, predicate, context)
- サマリ
-
obj
のプロパティ(要素)に対してpredicate
を_.each
で適用する
-
// `_.select` として別名定義
_.filter = _.select = function(obj, predicate, context) {
// 結果を初期化
var results = [];
// `predicate` のコンテキスト(`this`)設定
predicate = cb(predicate, context);
// `obj`ループ
_.each(obj, function(value, index, list) {
// `predicate`な値の場合、結果に積む
if (predicate(value, index, list)) results.push(value);
});
// 結果を返す
return results;
};
_.reject(obj, predicate, context)
- サマリ
-
_.negate()
を使ってサクッと実装js _.reject = function(obj, predicate, context) { // `_.nagate()`で`predicate`の否定を使ってサクッと実装 return _.filter(obj, _.negate(cb(predicate)), context); };
-
_.every(obj, predicate, context)
- サマリ
-
predicate
が成立しない場合、即時return false
とする - メソッド末尾到達で
true
を返す
-
// `_.all`で別名定義
_.every = _.all = function(obj, predicate, context) {
// `predicate`の`this`設定
predicate = cb(predicate, context);
// 配列でない場合、`obj`の全プロパティ名を取得
var keys = !isArrayLike(obj) && _.keys(obj),
// `obj`の長さを取得
length = (keys || obj).length;
// `obj`のプロパティ(要素)長分ループ
for (var index = 0; index < length; index++) {
// 対象キー(プロパティか添え字)を取得
var currentKey = keys ? keys[index] : index;
// `predicate()`が成立しない場合、即`false`を返し、メソッド終了
if (!predicate(obj[currentKey], currentKey, obj)) return false;
}
// ここに来るときは`obj`全てのプロパティ値(要素)に対する`predicate`が`true`となる
return true;
};
_.some(obj, predicate, context)
- サマリ
-
predicate
な値を発見した時点で即時return true
- メソッド末尾到達→
predicate
な値が存在しない→return false
-
// `_.any` として別名定義
_.some = _.any = function(obj, predicate, context) {
// `predicate`の`this`設定
predicate = cb(predicate, context);
// `obj`が配列でない場合、プロパティ名を取得
var keys = !isArrayLike(obj) && _.keys(obj),
// `obj`のプロパティ(要素)長取得
length = (keys || obj).length;
// オブジェクト長分ループ
for (var index = 0; index < length; index++) {
// `predicate`確認用キー値を取得
var currentKey = keys ? keys[index] : index;
// `predicate`な値の場合、trueを返す
if (predicate(obj[currentKey], currentKey, obj)) return true;
}
// `predicate`な値が存在しないので`false`を返す
return false;
};
_.contains(obj, item, fromIndex, guard)
- サマリ
- 実態は
_.indexOf()
-
_.indexOf()
よ呼び出すために配列変換の前処理を記述している
- 実態は
// 別名定義
_.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
// 後述の`_.indexOf`で判定実行しているので、配列でないオブジェクトは配列に変換
if (!isArrayLike(obj)) obj = _.values(obj);
// `fromIndex`の確定, `gurar`の記述理由は不明
if (typeof fromIndex != 'number' || guard) fromIndex = 0;
// 実処理
return _.indexOf(obj, item, fromIndex) >= 0;
};
_.invoke(obj, method)
- サマリ
- 実態は
_.map(obj, method)
-
method
にはfunction
とstring
を渡すことができる-
function
の場合、method.apply(objの各プロパティ, slice.call(arguments, 2))
を実行 -
string
の場合、obj.method.apply(objの各プロパティ, slice.call(arguments, 2))
を実行
-
- 実態は
_.invoke = function(obj, method) {
// `method`の引数となる第3引数を切り出す
var args = slice.call(arguments, 2);
var isFunc = _.isFunction(method);
return _.map(obj, function(value) {
// `method`が`function`の場合、`method(args)`を実行し、
// `function`でない場合、`obj.method(args)`を実行するように変数代入
var func = isFunc ? method : value[method];
// `func`が`null`でない場合、`func`を適用する
return func == null ? func : func.apply(value, args);
});
};
_.pluck(obj, key)
- サマリ
-
obj
のkey
の値を返す。 - 実態は
_.map(obj, _.property(key))
-
_.pluck = function(obj, key) {
// `_.property`で`key`の値を返す関数を定義し、`_.map`で`obj`に順次適用する
return _.map(obj, _.property(key));
};
_.where(obj, attrs)
-
obj
からattrs
をもつオブジェクトを返す
_.where = function(obj, attrs) {
return _.filter(obj, _.matcher(attrs));
};
_.findWhere(obj, attrs)
-
obj
からattrs
を持つ最初のオブジェクトを返す
_.findWhere = function(obj, attrs) {
return _.find(obj, _.matcher(attrs));
};
_.max(obj, iteratee, context)
-
obj
内の最大値を返す -
iteraee
で比較値を指定できる
_.max = function(obj, iteratee, context) {
var result = -Infinity, lastComputed = -Infinity,
value, computed;
// `iteratee`が存在しない場合
if (iteratee == null && obj != null) {
// 配列ならそのまま、そうでないならプロパティ値を抽出する
obj = isArrayLike(obj) ? obj : _.values(obj);
// 配列長(プロパティ長)分ループ
for (var i = 0, length = obj.length; i < length; i++) {
// 比較値`obj`から比較値を取得する
value = obj[i];
// 最大値を更新している場合
if (value > result) {
// 最大値を更新する
result = value;
}
}
// `iteratee`が存在する場合
} else {
// `iteratee`の`this`を設定する
iteratee = cb(iteratee, context);
_.each(obj, function(value, index, list) {
// `iteratee`から比較値を取得する
computed = iteratee(value, index, list);
// 最大値の更新またはループ初回の場合
if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
// 最大値を更新する
result = value;
// 比較最大値を更新する
lastComputed = computed;
}
});
}
// 最大値を返す
return result;
};
_.min(obj, iteratee, context)
-
_.max
とほぼ同一なので省略
_.shuffle(obj)
_.shuffle = function(obj) {
// 配列形式へ変換する
var set = isArrayLike(obj) ? obj : _.values(obj);
// 対象オブジェクト長を取得する
var length = set.length;
// 処理結果格納変数を初期化する
var shuffled = Array(length);
// オブジェクト長分ループ
for (var index = 0, rand; index < length; index++) {
// 0〜`index`の範囲で乱数を生成する
rand = _.random(0, index);
// 乱数が対象`index`でない場合、挿入位置にすでにある値を末尾に移動する
if (rand !== index) shuffled[index] = shuffled[rand];
// ランダムに代入する
shuffled[rand] = set[index];
}
// 結果を返す
return shuffled;
};
_.sample(obj, n, guard)
-
obj
からn
子の要素をランダムに返す
_.sample = function(obj, n, guard) {
// `n`を指定していない場合
if (n == null || guard) {
// `obj`を配列に変換する
if (!isArrayLike(obj)) obj = _.values(obj);
// `_.random`で乱数を生成し、`obj`の要素を1つ返す
return obj[_.random(obj.length - 1)];
}
// `obj`をランダムに並び替え、`n`個返す
return _.shuffle(obj).slice(0, Math.max(0, n));
};
_.sortBy(obj, iteratee, context) {
-
obj
を昇順ソートする - 比較値の導出には
iteratee
を利用する
_.sortBy = function(obj, iteratee, context) {
// `iteratee`内の`this`を`context`に設定する
iteratee = cb(iteratee, context);
// `obj`を`{value, index, criteria}`に変換する
// `sort`を適用する
// `_.pluck`で`value`(`obj`のプロパティ)を配列にして返す
return _.pluck(_.map(obj, function(value, index, list) {
return {
value: value,
index: index,
criteria: iteratee(value, index, list)
};
}).sort(function(left, right) {
// 比較値を取得する
var a = left.criteria;
var b = right.criteria;
if (a !== b) {
// `a`が`b`より大きい
if (a > b || a === void 0) return 1;
// `a`が`b`より小さい
if (a < b || b === void 0) return -1;
}
return left.index - right.index;
}), 'value');
};
_.groupBy(list, iteratee, [context])
-
iteratee
の計算結果に基づき、list
を分割する` - メイン処理は
group()
に記述している
var group = function(behavior) {
return function(obj, iteratee, context) {
// 結果代入変数を初期化する
var result = {};
// `this`などを設定する
iteratee = cb(iteratee, context);
// 実処理実行ループ
_.each(obj, function(value, index) {
// valueをkeyにマップする
var key = iteratee(value, index, obj);
// 求めた結果を`behavier`に渡すことで、実処理を実行する
behavior(result, value, key);
});
// 結果を呼び出し元へ返す
return result;
};
};
_.groupBy = group(function(result, value, key) {
// 同一`key`が存在する場合、配列追加する
if (_.has(result, key)) result[key].push(value);
// 同一`key`が存在しない場合、新規追加する
else result[key] = [value];
});
_.indexBy
_.indexBy = group(function(result, value, key) {
// `key`を`result`のプロパティ名として、`value`を代入する
result[key] = value;
});
_.countBy
_.countBy = group(function(result, value, key) {
// 結果に同一`key`が存在する場合、インクリメントする
if (_.has(result, key)) result[key]++;
// 初出現の`key`の場合、1から始まる
else result[key] = 1;
});
_.toArray(obj)
-
obj
を配列に変換する
_.toArray = function(obj) {
// `false`の場合、から配列を返す
if (!obj) return [];
// 配列の場合、配列コピーを返す
if (_.isArray(obj)) return slice.call(obj);
// 配列ライクの場合、`obj`の各プロパティを`_.map`で配列化して返す
if (isArrayLike(obj)) return _.map(obj, _.identity);
// `obj`プロパティ値を配列化して返す
return _.values(obj);
};
_.size(obj)
-
obj
の長さを返す
_.size = function(obj) {
// `null`の場合、0を返す
if (obj == null) return 0;
// 配列ライクの場合、`length`プロパティを返す
// それ以外の場合、`obj`のキー数を返す
return isArrayLike(obj) ? obj.length : _.keys(obj).length;
};
_.partition(obj, predicate, context)
- obj
の各要素値がpredicate
か否かで配列に分割する
_.partition = function(obj, predicate, context) {
predicate = cb(predicate, context);
// 分割値代入先変数を初期化する
var pass = [], fail = [];
// `obj`のプロパティに`predicate`を適用し、分割する
_.each(obj, function(value, key, obj) {
// `predicate`であるか計算する → 結果に応じて`pass`か`fail`に積む
(predicate(value, key, obj) ? pass : fail).push(value);
});
return [pass, fail];
};
_.first(array, n, guard)
-
array
の先頭要素を返す
- n
を与えた場合、先頭からn
番目の要素までを返す
// 別名を定義する
_.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0;
// `n`が指定されていない場合、`array`の先頭を返す
if (n == null || guard) return array[0];
// `array`の先頭から`n`番目までの要素を返す
return _.initial(array, array.length - n);
};
_.initial(array, n, guard)
-
array
の最後の要素を除いた破裂を返す - nを指定した場合は、
array
の先頭からarray.length-n
までを返す
_.initial = function(array, n, guard) {
// `array`の先頭から`array.length-n`番目までを返す
return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
};
_.last(array, n, guard)
-
array
最後の要素を返す -
n
を指定した場合、最後から個
目までを返す
_.last = function(array, n, guard) {
if (array == null) return void 0;
// 最後の要素を返す
if (n == null || guard) return array[array.length - 1];
// 最後から`n`個目までの要素を返す
// 実質`array.slice(array.length - n)`
return _.rest(array, Math.max(0, array.length - n));
};
_.rest(array, n, guard)
-
array
のn
以降の要素を全て返す
_.rest = _.tail = _.drop = function(array, n, guard) {
// `array.slice(n)`
return slice.call(array, n == null || guard ? 1 : n);
};
_.compact(array)
- falsyな値を除外する
_.compact = function(array) {
return _.filter(array, _.identity);
};
_.flatten(array, shallow)
- ネストしている
array
のネストを解除する
var flatten = function(input, shallow, strict, startIndex) {
var output = [], idx = 0;
for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
var value = input[i];
// 配列か引数の場合
if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
// シャロー指定していない場合、再帰的にネスト解除する
if (!shallow) value = flatten(value, shallow, strict);
var j = 0, len = value.length;
output.length += len;
// 対象`value`文ループする
while (j < len) {
// 結果を格納する
output[idx++] = value[j++];
}
} else if (!strict) {
// 結果を格納する
output[idx++] = value;
}
}
return output;
};
_.flatten = function(array, shallow) {
return flatten(array, shallow, false);
};
_.without(array, arguments...)
-
array
の中からarguments
に存在しない値を配列形式で返す
_.without = function(array) {
// `array`と第2引数以降の値の差を返す
return _.difference(array, slice.call(arguments, 1));
};
_.uniq(array, isSorted, iteratee, context)
- 重複値を除外する
- 重複判定には
_.contains
を使用 - ソート済み状態で処理を分岐する
_.uniq = _.unique = function(array, isSorted, iteratee, context) {
// `isSorted`が`bool`でない場合
if (!_.isBoolean(isSorted)) {
// 仮引数とインスタンスを調整する
context = iteratee;
iteratee = isSorted;
isSorted = false;
}
// コールバックを設定する
if (iteratee != null) iteratee = cb(iteratee, context);
var result = [];
var seen = [];
// `array`長分ループする
for (var i = 0, length = getLength(array); i < length; i++) {
var value = array[i],
// 基準値計算処理が渡されている場合、計算する
computed = iteratee ? iteratee(value, i, array) : value;
if (isSorted) {
if (!i || seen !== computed) result.push(value);
seen = computed;
} else if (iteratee) {
// 未出現の値の場合
if (!_.contains(seen, computed)) {
// 出現値管理変数に出現値を積む
seen.push(computed);
// 結果に積む
result.push(value);
}
} else if (!_.contains(result, value)) {
// 結果に積む
result.push(value);
}
}
return result;
};
_.union(array...)
- 引数の配列を結合&ユニークな要素のみに変換する
-
fatten
と_.uniq
の合わせ技js _.union = function() { return _.uniq(flatten(arguments, true, true)); };
_.intersection(array)
- 配列内の要素に共通する値を求める
_.intersection = function(array) {
// 結果格納変数を初期化する
var result = [];
// 計算対象引数の数を取得する
var argsLength = arguments.length;
// `array`長分ループする
for (var i = 0, length = getLength(array); i < length; i++) {
// 計算対象となる値を取得する
var item = array[i];
// 共通と判明しているなら次のループに移る
if (_.contains(result, item)) continue;
// 計算対象引数分ループする
for (var j = 1; j < argsLength; j++) {
// 別配列に存在しない場合、ループを抜ける(配列内に共通する値がない)
if (!_.contains(arguments[j], item)) break;
}
// 直前のループが最後まで回っている場合(共通する値が存在する)、結果に積む
if (j === argsLength) result.push(item);
}
// 結果を返す
return result;
};
_.difference = function(array...)
- 差集合を返す
_.difference = function(array) {
// 第2引数以降の配列のネストを解除する
var rest = flatten(arguments, true, true, 1);
// ネスト解除した配列に含まれていない要素のみ返す
return _.filter(array, function(value){
return !_.contains(rest, value);
});
};
_.zip(array1, array2...)
- 引数の各配列の同一インデックス要素が同一配列内に入るように組み替える
_.zip = function() {
return _.unzip(arguments);
};
_.unzip(array)
- 2次元配列
array
内の各配列を同一インデックス要素が同一配列内に入るように組み替える
_.unzip = function(array) {
// `array`の最大配列長を求め、その分の長さの配列を生成する
var length = array && _.max(array, getLength).length || 0;
var result = Array(length);
// 排列を組み替える
for (var index = 0; index < length; index++) {
result[index] = _.pluck(array, index);
}
return result;
};
_.object(list, values)
-
list
をobject
に変換する
_.object(list, values) {
// 結果変数を初期化する
var result = {};
// `list`長分ループする
for (var i = 0, length = getLength(list); i < length; i++) {
if (values) {
// `{list[i]: values[i]}`
result[list[i]] = values[i];
} else {
// `list[i]`を`{list[i][0]: list[i][1]}`に変換する
result[list[i][0]] = list[i][1];
}
}
// 結果を返す
return result;
};
_.findIndex(array, predicate, context)
-
array
内からpredicate
な値の添え字を返す- 複数の値が存在する場合、最初の添え字を返す
function createPredicateIndexFinder(dir) {
return function(array, predicate, context) {
// `predicate`の`context`を設定する
predicate = cb(predicate, context);
// 配列長を取得する
var length = getLength(array);
// `dir`(おそらくdirectionが由来)に基づき、走査対象インデックスを定める
var index = dir > 0 ? 0 : length - 1;
// 配列長分ループする
for (; index >= 0 && index < length; index += dir) {
// `array`の要素が`predicate`な値である場合、インデックスを返す
if (predicate(array[index], index, array)) return index;
}
return -1;
};
}
_.findIndex = createPredicateIndexFinder(1);
_.findLastIndex
- (array, predicate, context)
- 複数の値が存在する場合、最後の添え字を返す
_.findLastIndex = createPredicateIndexFinder(-1);
_.sortedIndex(array, obj, iteratee, context)
- 昇順ソート済みの
array
内からobj
が挿入されるインデックスを返す-
iteratee
にて、比較値の指定を可能
-
_.sortedIndex = function(array, obj, iteratee, context) {
iteratee = cb(iteratee, context, 1);
// 初期化する
var value = iteratee(obj);
var low = 0, high = getLength(array);
// バイナリーサーチ
while (low < high) {
// 中間となるインデックスを取得する
var mid = Math.floor((low + high) / 2);
// 比較値が`value`より小さい場合、2分割後半を探索対象とする
// 大きい場合、2分割前半を探索対象とする
if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
}
return low;
};
_.indexOf(array, item, idx)
-
array
内の要素がitem
であるインデックスを返す-
item
な要素が2つ以上の場合より前のインデックスを返す
-
function createIndexFinder(dir, predicateFind, sortedIndex) {
return function(array, item, idx) {
var i = 0, length = getLength(array);
if (typeof idx == 'number') {
// 先頭からの探索の場合
if (dir > 0) {
// 探索開始位置を決定する
i = idx >= 0 ? idx : Math.max(idx + length, i);
// 末尾からの探索の場合
} else {
// 探索開始位置を決定する
length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
}
} else if (sortedIndex && idx && length) {
// `array`内要素から`item`を探索する
idx = sortedIndex(array, item);
// `item`と同値な`array`要素が見つかった場合、インデックスを返す
return array[idx] === item ? idx : -1;
}
if (item !== item) {
idx = predicateFind(slice.call(array, i, length), _.isNaN);
return idx >= 0 ? idx + i : -1;
}
// 探索ループ
for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
// `array`の要素が`item`であるインデックスを返す
if (array[idx] === item) return idx;
}
return -1;
};
}
_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
_.lastIndexOf(array, item, idx)
-
array
内の要素がitem
であるインデックスを返す-
item
な要素が2つ以上の場合より後のインデックスを返すjs _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
-
_.range(start, stop, step)
- 指定範囲の値を要素に持つ配列を生成する
_.range = function(start, stop, step) {
// `stop`が渡されていない場合、`start`を`stop`に置き換える
if (stop == null) {
stop = start || 0;
start = 0;
}
// `step`が渡されていない場合`1`とする
step = step || 1;
// 必要な配列長を求め、配列を生成する
var length = Math.max(Math.ceil((stop - start) / step), 0);
var range = Array(length);
// `step`加算しつつ配列に積んでいく
for (var idx = 0; idx < length; idx++, start += step) {
range[idx] = start;
}
// 結果を返す
return range;
};
_.keys(obj)
-
obj
の列挙可能なプロパティ名を配列に積めて返す
_.keys = function(obj) {
// オブジェクトでない場合、から配列を返す
if (!_.isObject(obj)) return [];
`Object.keys`定義済みの場合、`Object.keys(obj)`の戻り値を返す
if (nativeKeys) return nativeKeys(obj);
var keys = [];
// `obj`の`key`を`keys`に積む
for (var key in obj) if (_.has(obj, key)) keys.push(key);
// Ahem, IE < 9. とのこと
if (hasEnumBug) collectNonEnumProps(obj, keys);
// 結果を返す
return keys;
};
_.allKeys(obj)
-
obj
のプロパティ名を配列に積めて返す
_.allKeys = function(obj) {
// オブジェクトでない場合、空配列を返す
if (!_.isObject(obj)) return [];
var keys = [];
// `obj`のプロパティ名を`keys`に積む
for (var key in obj) keys.push(key);
// Ahem, IE < 9. とのこと
if (hasEnumBug) collectNonEnumProps(obj, keys);
// 結果を返す
return keys;
};
_.values(obj)
-
obj
のプロパティ値を配列として返す
_.values = function(obj) {
// `obj`のプロパティ名を取得する
var keys = _.keys(obj);
// `obj`のプロパティ長を取得する
var length = keys.length;
// 結果を格納する配列を初期化する
var values = Array(length);
// プロパティ長分ループする
for (var i = 0; i < length; i++) {
// `obj`のプロパティ値を積める
values[i] = obj[keys[i]];
}
// 結果を返す
return values;
};
_.mapObject(obj, iteratee, context)
- オブジェクトの各プロパティに
iteratee
を適用した結果を返す
_.mapObject = function(obj, iteratee, context) {
// `iteratee`の`this`を設定する
iteratee = cb(iteratee, context);
var keys = _.keys(obj),
length = keys.length,
results = {},
currentKey;
// `obj`のプロパティ長分ループする
for (var index = 0; index < length; index++) {
// 処理対象プロパティ名を取得する
currentKey = keys[index];
// `obj`プロパティ値に`iteratee`を適用し、結果を積む
results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
}
// 結果を返す
return results;
};
_.pairs(obj)
-
obj
の各プロパティ名とプロパティ値を[プロパティ名, プロパティ値]
に変換して配列に積める
_.pairs = function(obj) {
// `obj`のプロパティ名を取得する
var keys = _.keys(obj);
// `obj`のプロパティ長を取得する
var length = keys.length;
// 結果格納変数を取得する
var pairs = Array(length);
// `obj`プロパティ長分ループする
for (var i = 0; i < length; i++) {
pairs[i] = [keys[i], obj[keys[i]]];
}
// 結果を返す
return pairs;
};
_.invert(obj)
-
obj
を{プロパティ値: プロパティ名}
に変換する
_.invert = function(obj) {
// 結果格納変数を初期化する
var result = {};
// `obj`のプロパティ名を取得する
var keys = _.keys(obj);
// `obj`プロパティ長分ループする
for (var i = 0, length = keys.length; i < length; i++) {
// プロパティ名とプロパティ値を入れ替える
result[obj[keys[i]]] = keys[i];
}
// 結果を返す
return result;
};
_.functions(obj)
-
obj
のメソッドを配列で返す
_.functions = _.methods = function(obj) {
// 結果格納変数を初期化する
var names = [];
// `obj`プロパティ名分ループする
for (var key in obj) {
// プロパティが関数の場合、結果に積む
if (_.isFunction(obj[key])) names.push(key);
}
// 昇順ソートし、結果を返す
return names.sort();
};
_.extend = createAssigner(obj)
var createAssigner = function(keysFunc, undefinedOnly) {
return function(obj) {
// 引数の数を取得する
var length = arguments.length;
// 引数が2個未満の場合、`obj`を返す
if (length < 2 || obj == null) return obj;
// 引数の数ループする
for (var index = 1; index < length; index++) {
// 対象引数を取得する
var source = arguments[index],
// `source`のプロパティ名を取得する
keys = keysFunc(source),
// プロパティ長を取得する
l = keys.length;
// プロパティ長分ループする
for (var i = 0; i < l; i++) {
// プロパティ名の1つを取得する
var key = keys[i];
// プロパティが未定義の場合、`obj`のプロパティに`source`のプロパティを1つ突っ込む
if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
}
}
// 結果を返す
return obj;
};
};
_.extend = createAssigner(_.allKeys);
_.extendOwn(dst, src)
-
src
の列挙可能プロパティのみdst
ヘシャローコピースル
_.extendOwn = _.assign = createAssigner(_.keys);
_.findKey(obj, predicate, context)
-
predicate
なobj
のプロパティ名を返す
_.findKey = function(obj, predicate, context) {
predicate = cb(predicate, context);
// `obj`のプロパティ名を取得する
var keys = _.keys(obj), key;
// `obj`プロパティ長分ループする
for (var i = 0, length = keys.length; i < length; i++) {
// 対象プロパティを取得する
key = keys[i];
// 対象プロパティが`predicate`な場合、そのプロパティ名を返す
if (predicate(obj[key], key, obj)) return key;
}
};
_.pick(object, oiteratee, context)
-
object
からoiteratee
がtrue
となるプロパティのみ抽出する
_.pick = function(object, oiteratee, context) {
var result = {}, obj = object, iteratee, keys;
// 引数を渡していない場合、空オブジェクトを返す
if (obj == null) return result;
// `oiteratee`が関数の場合
if (_.isFunction(oiteratee)) {
// `obj`のすべてのプロパティ名を取得する
keys = _.allKeys(obj);
// `oiteratee`を設定する
iteratee = optimizeCb(oiteratee, context);
} else {
keys = flatten(arguments, false, false, 1);
// `obj`が`key`となるプロパティ名が存在するか判定する関数を定義する
iteratee = function(value, key, obj) { return key in obj; };
obj = Object(obj);
}
for (var i = 0, length = keys.length; i < length; i++) {
// 対象プロパティ名を取得する
var key = keys[i];
// プロパティ値を取得する
var value = obj[key];
// `obj`に`key`プロパティが存在する場合、結果に積む
if (iteratee(value, key, obj)) result[key] = value;
}
return result;
};
_.omit(obj, iteratee, context)
-
obj
からiteratee
がfalse
となるプロパティを抽出する
_.omit = function(obj, iteratee, context) {
// `iteratee`が関数の場合
if (_.isFunction(iteratee)) {
// `iteratee`の真偽の反転する関数を定義する
iteratee = _.negate(iteratee);
} else {
var keys = _.map(flatten(arguments, false, false, 1), String);
iteratee = function(value, key) {
return !_.contains(keys, key);
};
}
// _
return _.pick(obj, iteratee, context);
};
_.defaults(object, defaults)
-
object
のプロパティの標準値を設定する
_.defaults = createAssigner(_.allKeys, true);
_.create(prototype, props)
_.create = function(prototype, props) {
var result = baseCreate(prototype);
if (props) _.extendOwn(result, props);
return result;
};
_.clone(obj)
-
obj
コピーを返す- ネスとしているプロパティはシャローコピー
_.clone = function(obj) {
// オブジェクトでない場合、そのまま返す
if (!_.isObject(obj)) return obj;
// 配列の場合`slice`でコピーを返し、配列でない場合`_.extend`で空オブジェクトを基にコピーを生成する
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
_.tap(obj, interceptor)
-
obj
を引数に取るinterceptor
を呼び出す
_.tap = function(obj, c) {
interceptor(obj);
return obj;
};
_.isMatch(object, attrs)
-
object
のプロパティにattrs
が存在するか返す
_.isMatch = function(object, attrs) {
// `attrs`のプロパティ名とプロパティ長を取得kする
var keys = _.keys(attrs), length = keys.length;
if (object == null) return !length;
var obj = Object(object);
for (var i = 0; i < length; i++) {
// 処理対象プロパティ名を決定する
var key = keys[i];
// `attrs`のプロパティ値と`obj`のプロパティ値が異なる or `attrs`のプロパティ名が`obj`のプロパティ名に存在しないばい
if (attrs[key] !== obj[key] || !(key in obj)) return false;
}
// `object`に`attrs`が存在する場合、`true`を返す
return true;
};
_.isEmpty(obj)
-
obj
が空であるか判定する
_.isEmpty = function(obj) {
// `null`は空とする
if (obj == null) return true;
// 配列長0の場合は空とする
if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
// `obj`のプロパティ長が0は空とする
return _.keys(obj).length === 0;
};
_.isElement(obj)
-
obj
がエレメントであるか返す
_.isElement(obj) {
// @see https://developer.mozilla.org/ja/docs/Web/API/Node/nodeType
return !!(obj && obj.nodeType === 1);
};
_.isArray(obj)
`Array.isArray`未定義の場合、独自メソッドを使用する
_.isArray = nativeIsArray || function(obj) {
// 実行環境に任せる
return toString.call(obj) === '[object Array]';
};
_.isObject(obj)
-
obj
がオブジェクトであるか判定する
_.isObject = function(obj) {
// 型名(`typeof`)で判定する
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
};
_.noConflict
- 他で定義されている
_
との衝突を避けるため、underscoreをオブジェクトとして返す
_.noConflict = function() {
// 事前に定義されている`_`をグローバルに保持する
root._ = previousUnderscore;
// underscoreオブジェクトを返す
return this;
};
_.identity(value)
- 引数をそのまま返す
_.identity = function(value) {
// 引数である`value`を返す
return value;
};
_.constant(value)
-
value
を返す関数を返す - 使用方法
_constant(5)()
_.constant = function(value) {
// 関数を返す
return function() {
// `value`を返す
return value;
};
};
_.property(key)
- オブジェクトの
key
プロパティ値を返す関数を返す
var property = function(key) {
// 引数`obj`を受け取り、`key`プロパティの値を返す
return function(obj) {
return obj == null ? void 0 : obj[key];
};
};
// `property`へ
_.property = property;
_.propertyOf(obj)
- プロパティ名を引数として、
obj
のプロパティ値を返す関数を返す
_.propertyOf = function(obj) {
// `obj`の`key`プロパティ値を返す関数を返す
// `_.propertyOf(obj)(key)` で`obj.key`を返す
return obj == null ? function(){} : function(key) {
return obj[key];
};
};
_.matcher(attrs)
- オブジェクトのプロパティに
attrs
が存在するか判定する関数を返す
_.matcher = _.matches = function(attrs) {
attrs = _.extendOwn({}, attrs);
// `_.isMatch`で`attrs`を存在確認する関数を返す
return function(obj) {
return _.isMatch(obj, attrs);
};
};
_.times(n, iteratee, context)
-
iteratee
をn
回呼び出し、結果を配列で返す
_.times = function(n, iteratee, context) {
var accum = Array(Math.max(0, n));
iteratee = optimizeCb(iteratee, context, 1);
// `iteratee`を`n`回呼び出し、結果を配列に格納する
for (var i = 0; i < n; i++) accum[i] = iteratee(i);
return accum;
};
_.random(min, max)
-
min
〜max
の乱数を返す
_.random = function(min, max) {
if (max == null) {
max = min;
min = 0;
}
// 「最小値」と「最小値から最大値の差分*割合」で範囲内の乱数を求める
return min + Math.floor(Math.random() * (max - min + 1));
};
_.now()
- 1970/1/1/0:0:0からの経過時間をmsで返す
_.now = Date.now || function() {
// `Date.now`が未定義の場合、`Date.getTime`を使用する
return new Date().getTime();
};
_.result(object, property, fallback)
-
property
がobject
のメソッドの場合、object.property()
を実行し、その戻り値を返す -
property
がobject
のメソッドでないプロパティの場合、object.property
を返す
_.result = function(object, property, fallback) {
var value = object == null ? void 0 : object[property];
if (value === void 0) {
value = fallback;
}
return _.isFunction(value) ? value.call(object) : value;
};
_.uniqueId(prefix)
- ユニークな値を返す
- ID値はクロージャで管理している
var idCounter = 0;
_.uniqueId = function(prefix) {
// `+ ''`で文字列へ変換する
var id = ++idCounter + '';
// `prefix`指定がある場合、プリフィックスを付与する
return prefix ? prefix + id : id;
};
_.templateSettings
- テンプレート判定正規表現を変更する
- 評価、補間、エスケープの3種類を設定可能
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
`
### `_.chain(obj)`
```js
_.chain = function(obj) {
// see `var _ = function(obj) ... `
var instance = _(obj);
// see `var result = function ...`
instance._chain = true;
return instance;
};
公開メソッド以外
ルートオブジェクトの確立
var root = this;
Establish the root object, window in the browser, or exports on the server.
「ブラウザなら window
、サーバーなら exports
」とのこと。
バージョン定義
_.VERSION = '1.8.3';