Underscore.jsおさらい4(Functions)
bind _.bind(function, object, *arguments)
関数のオブジェクト束縛。関数を変数にして引き回せるJavaScriptならでは。
Javaな自分には最初理解できなんだ。
関数内のthisをオブジェクトに割り当てる。
今は標準でbindが実装されているが、実装が曖昧という記述も見たのでしばらくは使うかも。
var func = function(greeting){ return greeting + ': ' + this.name }; func = _.bind(func, {name: 'moe'}, 'hi'); func(); => 'hi: moe'
bindAll _.bindAll(object, *methodNames)
methodNamesで指定したメソッドだけbindする。未指定なら全メソッドが対象。
var buttonView = { label : 'underscore', onClick: function(){ return 'click:' + this.label; }, onHover: function(){ return 'hovering:' + this.label; } }; _.bindAll(buttonView, 'onHover'); var click = buttonView.onClick; var hover = buttonView.onHover; click(); => click:undefined hover(); => hovering:underscore
partial _.partial(function, *arguments)
bindはthisをbindするが、partialは引数をbindする感じ。
第一引数はbindせずに、第二引数をbindしたい、という場合は「_」を使えばいい。
var subtract = function(a, b) { return b - a; }; sub5 = _.partial(subtract, 5); sub5(20); => 15 // Using a placeholder subFrom20 = _.partial(subtract, _, 20); subFrom20(5); => 15
memoize _.memoize(function, [hashFunction])
関数をキャッシュして処理を早くする用途で使われる。
var fibonacci = _.memoize(function(n) { return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2); });
delay _.delay(function, wait, *arguments)
setTimeoutに近い感じで使える。waitミリ秒後にfunctionを実行する。
var log = _.bind(console.log, console); _.delay(log, 1000, 'logged later'); => 'logged later' // 1秒後にコンソール出力
defer _.defer(function, *arguments)
コールスタックが空になるまで処理を待つ。setTimeoutで0ミリ秒指定と似た感じ。
function() { alert('1'); _.defer(function(){ alert('deferred'); }); alert('2'); } => 1, 2, deferrdの順にalert表示
throttle _.throttle(function, wait, [options])
関数の呼び出しを制限できる。
waitミリ秒以内に関数が再度呼び出されても実行されないようになる。
optionsに{leading: false}を指定すれば、初回実行も指定秒待ってから実行される。
{trailing: false}を指定すれば、指定時間内に後続の呼び出しがあれば、待たずに実行がキャンセルされる。
特にleading: falseの時とか、特に引数とかbindした関数使うときは注意。
var f = _.throttle(function(n) {console.log(n + ':' + _.now());}, 100); f(1); => 現在ミリ秒表示 f(2); => 1回目から100ミリ秒以上経っていれば実行、経っていなければ100ミリ秒後まで待って実行 var f = _.throttle(function() {console.log('-----:' + _.now());}, 100, {leading: false}); f(); => 100ミリ秒後に実行されるようにtimerセット f(); => 開始から100ミリ秒以内であれば、1回目の呼び出しを破棄して開始から100ミリ秒後に実行されるようにtimerセット // 後勝ちになる var f = _.throttle(function() {console.log('-----:' + _.now());}, 100, {trailing: false}); f(); => 現在ミリ秒表示 f(); => 1回目から100ミリ秒以内であれば無視される、100ミリ秒以上なら実行
debounce _.debounce(function, wait, [immediate])
関数の呼び出しを制限できる。
throttleの{leading: false}と似たような動きになる。
immediateをtrueにすると、まず関数が実行されるのでthrottleの{trailing: false}と似た感じ。
once _.once(function)
一度しか実行できない関数にする。2回目以降の戻り値は1回目と同じ値になる。
var f = _.once(function() {console.log('-----:' + _.now());}); f(); => 実行 f(); => 実行されない
after _.after(count, function)
count回呼び出し以降しか実行されない。
var f = _.after(3, function() {console.log('-----:' + _.now());}); f(); => 実行されない f(); => 実行されない f(); => 実行 f(); => 実行
before _.before(count, function)
最初のcount - 1回までしか実行されない。
onceは_.before(2, function)として実装されている。
var f = _.after(3, function() {console.log('-----:' + _.now());}); f(); => 実行 f(); => 実行 f(); => 実行されない f(); => 実行されない
wrap _.wrap(function, wrapper)
関数を別関数でラップして、元関数の前後に処理を入れられる。
AOPとかfilterとかそんなイメージ。
var hello = function(name) { return "hello: " + name; }; hello = _.wrap(hello, function(func) { return "before, " + func("moe") + ", after"; }); hello(); => 'before, hello: moe, after'
negate _.negate(predicate)
predecateの戻り値(真偽値)を逆にする。
var f = _.negate(function(n){ return n % 2 == 0; }); _.find([-2, -1, 0, 1, 2], f); => -1
compose _.compose(*functions)
合成関数を作成する。
数学的にf(), g(), h()の合成関数はf(g(h()))となるらしいので、後ろの関数から順に処理される感じになる。
var greet = function(name){ return "hi: " + name; }; var exclaim = function(statement){ return statement.toUpperCase() + "!"; }; var welcome = _.compose(greet, exclaim); welcome('moe'); => 'hi: MOE!'
Function終了。タイマー系の理解がちょっと大変。