素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: すかいぷ:javascripter_  か javascripter あっと tsukkun.net skypeのほうがいいです

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));

のようにもできるけど、著しく可読性が落ちる。