このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

JavaScriptでユーザー定義の二項演算子

… なんてことは出来ませんよね。でも、二項演算子に見せかけるようにジタバタしてみましたよ。

まずは例題。

/** 集合の共通部分 */
function intersectionOfSets(a1, a2) {
  // 重複は除外されない
  return a1.filter(function(item) {return (a2.indexOf(item) > -1);});
}

/** 2つのオブジェクトを、順序に依存しないでマージする */
function merge(o1, o2) {
  var ks1 = Object.keys(o1);
  var ks2 = Object.keys(o2);
  if (intersectionOfSets(ks1, ks2).length !== 0) {
    throw new Error("Can not merge");
  }
  var r = {};
  ks1.forEach(function(k){r[k] = o1[k];});
  ks2.forEach(function(k){r[k] = o2[k];});
  return r;
}

mergeという関数は次のような感じ。


>>> merge({a:"foo", b:"bar"}, {x:1})

Object { a="foo", b="bar", x=1}

>>> merge({a:"foo", b:"bar"}, {a:1})

Error: Can not merge

このmergeを、2引数の関数じゃなくて中置ニ項演算子のように扱いたいのです。

オブジェクトのメソッドにすると少しニ項演算子っぽくなります。

Object.prototype.merge = function(obj) {
  return merge(this, obj);
};


>>> ({a:"foo", b:"bar"}).merge({x:1})

Object { a="foo", b="bar", x=1}

でも、演算子と言えばワードよりは記号ですよね。次のようにしてみましょう。

Object.prototype.$$ = function(obj) {
  return merge(this, obj);
};


({a:"foo", b:"bar"}) .$$ ({x:1})

Object { a="foo", b="bar", x=1}

.$$ という、3文字の記号による演算子のように見えなくもありません。関数名に使えて記号っぽい文字というと、ドル記号('$')とアンダースコア('_')、英大文字を使って .X、.H、.V なんかも記号っぽいかもしれません。でも、'+' とか '>' なんかを関数名に含めることはできません。次のようにすれば使えなくもないですが。

Object.prototype['+'] = function(obj) {
  return merge(this, obj);
};


>>> ({a:"foo", b:"bar"}) ['+'] ({x:1})

Object { a="foo", b="bar", x=1}

['+'] という4文字をひとつの演算子とみなすわけです。… しかし、クォートされた '+' なら我慢できそうですが、['+'] は面倒で耐えられないかも。

特定の状況下で可読性を上げるためには、演算子定義があると便利だな、と感じます。