不思議な空リスト

[ ] == false           //=> true
![ ]                   //=> false
[ ] == ![ ]            //=> true
if([ ]) alert('True')  //=> alert('True')

falseと==で比較して真になるという仕様の意味がわからない。

2010-02-23追記:

「Under Translation of ECMA-262 3rd Edition」という日本語文書があったので見てみた。 http://www2u.biglobe.ne.jp/~oz-07ams/2002/ecma262r3/index.html

11.9.3 抽象的等価比較アルゴリズム (The Abstract Equality Comparison Algorithm)

x と y を値とする比較 x==y は、 true または false を生成する。次のように比較は実行される:

1. Type(x) と Type(y) が異なる場合は、ステップ 14 へ。
2. Type(x) が Undefined ならば、 true を返す。
3. Type(x) が Null ならば、 true を返す。
4. Type(x) が Number でなければ、ステップ 11 へ。
5. x が NaN ならば、 false を返す。
6. y が NaN ならば、 false を返す。
7. x が y と同じ数ならば、 true を返す。
8. x が +0 で y が -0 ならば、 true を返す。
9. x が -0 で y が +0 ならば、 true を返す。
10. false を返す。
11. Type(x) が String ならば、x と y の文字シーケンスが完全に同じ(同じ長さで対応する位置に同じ文字がある)なら true を返し、そうでなければ false を返す。
12. Type(x) が Boolean ならば、 x と y がともに true かともに false なら true を返し、そうでなければ false を返す。
13. x と y が同じオブジェクトを参照しているか、または互いに結合しているオブジェクト(セクション13.1.2) を参照していれば true を返し、そうでなければ false を返す。
14. x が null で y が undefined ならば、 true を返す。
15. x が undefined で y が null ならば、 true を返す。
16. Type(x) が Number で Type(y) が String ならば、比較 x == ToNumber(y) の結果を返す。
17. Type(x) が String で Type(y) が Number ならば、比較 ToNumber(x) == y の結果を返す。
18. Type(x) が Boolean ならば、比較 ToNumber(x) == y の結果を返す。
19. Type(y) が Boolean ならば、比較 x == ToNumber(y) の結果を返す。
20. Type(x) が String か Number で Type(y) が Object ならば、比較 x == ToPrimitive(y) の結果を返す。
21. Type(x) が Object で Type(y) が String か Number ならば、比較 ToPrimitive(x) == y の結果を返す。
22. false を返す。

これを元に、

[ ] == false

の比較を追って解析していく。

1 → 19 で、

[ ] == ToNumber(false)
[ ] == +0                       // ToNumber(false) については、9.3 ToNumber に記述有り

さらに21で、

ToPrimitive([ ]) == +0
[ ]のDefaultValue(hint) == +0   // ToPrimitive([ ]) については、9.1 ToPrimitive に記述有り
[ ]のGet(toString) == +0        // DefaultValueについては 8.6.2.6 [[DefaultValue]] (hint) に記述有り
[ ].toString() == +0            // Get(toString)については 8.6.2.1 [[Get]] (P) に記述有り
"" == +0                        // [ ].toString は空文字列

こんどは17で、

toNumber("") == +0

toNumber("") については、「9.3.1 String 型に適用される ToNumber (ToNumber Applied to the String Type) 」に以下の記述がある。

文字列に適用される ToNumber は、入力文字列に 次の文法を適用する。文法が文字列を StringNumericLiteral として解釈不能ならば、 ToNumber の結果は NaN である。

StringNumericLiteral :::
  StrWhiteSpace(opt)
  StrWhiteSpace(opt) StrNumericLiteral StrWhiteSpace(opt)
(中略)
# StringNumericLiteral ::: [empty] の数学値は、 0 である。
(中略)
一旦数値文字列リテラルの厳密な数学値が決定されたら、 Number 型の値に丸められる。数学値が 0 ならば、丸められる値は、数値文字列リテラル内の最初の非空白文字が '-' でなければ +0 であり、 '-' ならば -0 である。

ここから、空文字列の場合も StringNumericLiteral と見なされ、その数学値は 0 であり、最終的な値は +0 となる。

従って、

+0 == +0

となり、上記アルゴリズム7で true となる。


長い。。。。。数学の証明問題みたい。MozillaサイトのJavaScriptリファレンスもざっと見たが、同じような事が別の書き方で書いてある。

つまり、空リストは、
・論理値と評価される文脈では、true となる*1
・数値や論理値と等値比較される文脈では 0 となる
という分かりにくい仕様だ。

*1:「9.2 ToBoolean」に記述がある