【Underscore.js】_.throttleを読んだ
jashkenas/underscoreの_.throttleを読んだ。
概要
_.throttle(function, wait, [options])
functionを一度目は即時実行して、二回目以降はwaitミリ秒待ってから実行する関数を返す。waitミリ秒までに複数回関数を実行しようとしても、最後に受け付けた関数のみが実行される。
function printCurrTime(num) { console.log(`now: ${_.now()} num: ${num}`); } var printTime = _.throttle(printCurrTime, 5000); printTime(0); printTime(1); // 実行されない printTime(2); // 実行されない printTime(3); // 実行されない printTime(4); // 実行されない printTime(5); // now: 1445396803605 num: 0 // now: 1445396808607 num: 5
ソースコード
_.throttle = function(func, wait, options) { var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; };
一度目の関数が実行された時刻をpreviousに代入し、クロージャーに渡している。 二回目以降、関数が呼ばれるたびに、残りの時間を設定したsetTimeoutを発行する。
参考
【Underscore.js】_.deferを読んだ
jashkenas/underscoreの_.deferを読んだ。
概要
_.defer(function, *arguments) ``` 現在のコールスタックがクリアされたあとに、functionを実行させる。 setTimeoutを0msで実行するのと似ている。 処理が重い計算や、HTMLのレンダリング等に使うと便利。
console.log('0'); (function(){ _.defer(function(){console.log('1');}); }()); console.log('2’); // 0, 2, 1
## ソースコード
.defer = .partial(.delay, , 1);
_.delayを1msで実行している。 ## 参考 [jashkenas/underscore](https://github.com/jashkenas/underscore)
【Underscore.js】_.memoizeを読んだ
jashkenas/underscoreの_.memoizeを読んだ。
概要
_.bind(function, object, *arguments)
一度計算した値をキャッシュしておく機能を関数に付け加える。
var num = 40; var fib = function(n) { return n < 2 ? n : fib(n - 1) + fib(n - 2); }; console.time('not memoize'); console.log(fib(num)); console.timeEnd('not memoize’); // not memoize: 1701.395ms var fib2 = _.memoize(function(n) { return n < 2 ? n : fib2(n - 1) + fib2(n - 2); }); console.time('memoize'); console.log(fib2(num)); console.timeEnd('memoize’); // memoize: 0.979ms
ソースコード
_.memoize = function(func, hasher) { var memoize = function(key) { var cache = memoize.cache; var address = '' + (hasher ? hasher.apply(this, arguments) : key); if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); return cache[address]; }; memoize.cache = {}; return memoize; };
hasherが与えられなければ、関数に与えられる引数をkeyにしたキャッシュ用の配列を内部で持っておき、キャッシュにヒットしたらそれを返している。
参考
【Underscore.js】_.sortedIndexを読んだ
jashkenas/underscoreの_.sortedIndexを読んだ。
概要
_.sortedIndex(list, value, [iteratee], [context])
ソートされているlistに対して、valueがどの位置に入るかを返す。
_.sortedIndex([10, 20, 30, 40, 50], 35); // 3
ソースコード
_.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); if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; } return low; };
while文の中で二分探索をしている。
参考
【Underscore.js】_.zipを読んだ
jashkenas/underscoreの_.zipを読んだ。
概要
_.zip(*arrays)
引数である各配列のindex値の値をまとめた配列を作る。返される配列のlengthは引数の中で1番長いlengthを持つ配列と同じ長さになる。
var x = _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); console.log(x); // [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]
ソースコード
_.zip = function() { return _.unzip(arguments); }; _.unzip = function(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; };
下記のコードで、引数のそれぞれの配列に対し、そのindex番目を結果にいれている。
for (var index = 0; index < length; index++) { result[index] = _.pluck(array, index); }
参考
【Underscore.js】_.uniqを読んだ
jashkenas/underscoreの_.uniqを読んだ。
概要
_.uniq(array, [isSorted], [iteratee])
arrayの各値の中で同じ値があった場合、1つだけにされ各値が重複のない配列として返される。配列がソートされている際に、isSortedをtrueにするとより高速に動作する。 値同士が等しいかどうかを評価する関数を渡すこともできる。
var list = [1, 10, 2, 3, 4, 1, 2, 3]; var x = _.uniq(list); console.log(x); // [1, 10, 2, 3, 4]
ソースコード
_.uniq = _.unique = function(array, isSorted, iteratee, context) { if (!_.isBoolean(isSorted)) { context = iteratee; iteratee = isSorted; isSorted = false; } if (iteratee != null) iteratee = cb(iteratee, context); var result = []; var seen = []; 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; };
iterateeが与えられた時のseenは、iterateeで各値を評価したものがpushされていく。
} else if (iteratee) { if (!_.contains(seen, computed)) { seen.push(computed); result.push(value); } }
参考
【Underscore.js】_.intersectionを読んだ
jashkenas/underscoreの_.intersectionを読んだ。
概要
_.intersection(*arrays)
第一引数の配列の各値の中で、第二引数以降のすべての配列に含まれている値を返す。
var x = _.intersection([1, 10, 10, 3], [3 ,190, 10], [1, 545, 3, 10]); console.log(x); // [10, 3]
ソースコード
_.intersection = function(array) { var result = []; var argsLength = arguments.length; 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; };
第一引数の各値が、第二引数以降の配列にも含まれているかを_.containを使って調べている。
for (var j = 1; j < argsLength; j++) { if (!_.contains(arguments[j], item)) break; } if (j === argsLength) result.push(item); }
上記の処理は、すべての配列にitem(第一引数の値)が含まれているかを調べている部分。 引数で与えられた配列の数だけjがインクリメントされていれば、すべての配列に値が含まれている。