ぶれすとつーる

だいたいjavascript

闇jser試験をといてみた。

以前、@uupaaさんが出題してた闇jser試験をふと思い出したので解いてみた。

true & undefined === false & undefined


まずは演算子の評価時の優先順位に着目してみる。

厳密等価比較(===)のほうがバイナリビット演算子(&)より優先度が高いことがわかる。

つまりこの式を置き換えると以下のように表せる

(true & (undefined === false)) & undefined

演算順序が分かったところで演算処理を見ていこう。


undefinedとfalseは厳密等価比較ではfalseになる。
これは見た通りなのでいいだろう。

つまり以下の式が最初の評価結果になる。

(true & false) & undefined

真偽値同士の論理積を計算するにあたってバイナリビット演算子の評価ステップを参照すると以下のようになっている。

Semantics
@ のところを上の生成規則のビット演算子として、生成規則 A : A @ B は、次のように評価される:

  1. A を評価。
  2. GetValue(Result(1)) を呼出す。
  3. B を評価。
  4. GetValue(Result(3)) を呼出す。
  5. ToInt32(Result(2)) を呼出す。
  6. ToInt32(Result(4)) を呼出す。
  7. ビット演算子 @ を Result(5) と Result(6) に適用する。結果は符号付 32 ビット整数である。
  8. Result(7) を返す。

とどのつまり両項を計算してからToInt32にかけて論理積計算するという内容です。
今、左項はtrue、右項はfalseとなっていて計算の余地はないのでそのままToInt32にかけます。
ToInt32の内部ではToNumberを通しているのでtrueは1、falseは0として評価されます。


つまり以下のような式に内部的に変換されています。

(1 & 0) & undefined

単純に括弧内を論理積で計算すると0が得られますね。
つまり2回目の評価結果は以下のようになります。

0 & undefined

こうなると先ほどと同様に両項にToInt32をかけるだけです。
ToInt32内部でToNumberメソッドがかけられると0はそのまま0を返しますが、undefinedはNaNを返します。


通常の型変換だとこれで終わりですがToInt32ではToNumber後の処理ステップに以下の記述があります。

  1. 入力引数に ToNumber を呼出す。
  2. Result(1) が NaN, +0, -0, +∞, or -∞ ならば、 +0 を返す。
  3. sign(Result(1)) * floor(abs(Result(1))) を算出する。
  4. Result(3) modulo 232 を算出する; すなわち、 Result(3) との数学的な差が数学的に 232 の整数倍であるような、大きさ 232 未満の正符号付き Number 型の 有限整数値 k である。
  5. Result(4) が 231 以上ならば、 Result(4) - 232 を返す。そうでなければ Result(4) を返す。

ToNumber後に値が「NaN, +0, -0, +∞, or -∞ ならば、 +0 を返す」とされているのでNaNを返すundefinedは最終的に+0を返します。


つまり先ほどの式は最終的に以下のように解釈されます。

0 & 0

これを論理積で計算して、答えは 0 ですね。

おしまい。