JavaScript Puzzlers 解答

昨日のパズルの解答。
まず、問題のスクリプトは以下のとおりでした。

function proveDoMorgan() {
  var a = true;
  var b = 2;
  if((a && b) == !(!a || !b)) {
    alert("Equal!");
  }
  else {
    alert("Not Equal!");
  }
}

proveDoMorgan();

このスクリプトは関数の名前から、ド・モルガンの定理
\overline{A \cdot B} = \overline{A} + \overline{B}
を証明しようとしているように見えます。確かにif文の条件式の内容は、上記の式の両辺の否定をとった形になっています。だとすると、当然if文の式は真となり、"Equals"と表示されるように思えます。しかし、実行してみると"Not Equal!"と表示されるはずです。*1

これは、(当たり前ですが)ド・モルガンの定理に反証が見つかったわけではなく、JavaScriptにおける短絡的論理演算子( && と || )の動作によるものです。JavaScriptの短絡的論理演算子の動作は、CやJavaのそれと同じく、式全体の真偽値が決定した段階で残りの式の評価をやめるのですが、式の値はtrueまたはfalseではなく、最後に評価された値になるのです。
つまりJavaScriptにおける短絡的論理演算子は、3項演算子(a?b:c)の特殊ケースとも言え、次のような書き換えができます。

 (a ? a : b) ⇒ (a || b)
 (!a ? a : b) ⇒ (a && b)

なので、proveDoMorgan関数内の条件式の右辺の値は true であるのに対して、左辺の値は 2 となり、 2 と true は同値ではないため、結果 else節の処理が実行されるのでした。

でもこれってperlrubyでも同じ動作になるみたいなので、スクリプト系の言語に慣れてる人にとっては結構当たり前なのかも。

*1:IE6.0とFirefox1.5とOpera8.5で確認