Object#tap
RubyのObject#tapがすごく便利。tapかわいいよtap - (rubikitch loves (Emacs Ruby CUI Books))に書いてある。これを使うと、selfを返さないメソッドを使ってもチェインできる。
JavaScriptだと、こんな感じ。
Object.prototype.tap = function (fn) { fn.call(this, this); return this; };
ただ、JavaScriptだとyieldブロックがないから、少し野暮ったい。もう少し動作を限定させて、
Object.prototype.tap = function (name) { this[name].apply(this, Array.slice(arguments, 1)); return this; }; [1, 2, 3] .tap('push', 4, 5, 6) // [1, 2, 3, 4, 5, 6] .tap('unshift', 0) // [0, 1, 2, 3, 4, 5, 6] .tap('splice', 3, 2) // [0, 1, 2, 5, 6] .reduce(function (a, b) a + b); // 14
のようにするといい。もう少し実用的な例も挙げる。
Object.prototype.tap = function (name) { this[name].apply(this, Array.slice(arguments, 1)); return this; }; new XMLHttpRequest() .tap('open', 'get', location.href, true) .tap('send', null) .tap('addEventListener', 'load', function (e) { console.log(e.target.responseText, e); }, false) .addEventListener('error', function (e) { console.error(e.target.responseText, e); }, false);
Ruby風の(一番上に載せた)tapを使うなら、method_caller(__proto__ = null - 素人がプログラミングを勉強するブログ)があったほうが使いやすい。
Object.prototypeを拡張するのが嫌なら、
function tap(object, fn) { fn.call(object, object); return object; } function methodCaller(prop) { var args = Array.slice(arguments, 1); return function (receiver) { return receiver[prop].apply(receiver, args); } } tap( tap( tap(new XMLHttpRequest(), methodCaller( 'open', 'get', location.href)), methodCaller( 'send', null)), methodCaller( 'addEventListener', 'load', function (e) { console.log(e.target.responseText); }, false));
のようにもできるけど、著しく可読性が落ちる。