JavaScriptの (抽象的)等価演算 (==)は、評価ロジックがやや複雑です。以下は、 Ecma-262.pdfの抜粋です。平易な英文ですので特に訳しません。
11.9.3 The Abstract Equality Comparison Algorithm
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
- If Type(x) is the same as Type(y), then
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
- If x is NaN, return false.
- If y is NaN, return false.
- If x is the same Number value as y, return true.
- If x is +0 and y is -0, return true.
- If x is -0 and y is +0, return true.
- Return false.
- If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
- If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
- Return true if x and y refer to the same object. Otherwise, return false.
- If x is null and y is undefined, return true.
- If x is undefined and y is null, return true.
- If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
- If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
- If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
- If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
- If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
- If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
- Return false.
このルールを具体的な例を用いて考えて行きます。
左辺が数値・右辺が文字列
alert(100 == "100.00");
実行結果
true
- 左辺は数値型・右辺文字列型→4
- 右辺を数値型に変換して再評価
- 右辺を数値型に変換すると100
- 「100 == 100」として再評価
- 右辺左辺ともに数値型で同じ値である→1-c-iii
- return true
左辺も右辺も文字列
alert("100" == "100.00");
実行結果
false
- 左辺・右辺は同じ型で文字列型→1-d
- 文字列長や内容が異なる
- return false
値が数値の「100」と評価されうる文字列でも、右辺左辺両方が文字列の場合とどちらかが数値の場合で異なるので注意が必要です。
空の配列同士の比較
alert([] == []);
実行結果
false
どちらも空の配列なので直感的にtrueを期待する人が多いと思います。しかし、これはfalseになります。
ルールを順に追ってみます。
- 右辺も左辺も配列で同じ型→1
- UndefinedでもNullでも数値型でも文字列型でも真偽値型でもない→f
- 同じオブジェクトを参照しているわけではない
- return false
となり、falseと評価されるのです。
一方が否定の空の配列の比較
alert([] == ![]);
実行結果
true
右辺と左辺が明らかに異なるため、直感的にはfalseを期待するでしょうが、これはtrueになります。
ルールを順に追ってみます。
- 左辺は配列型・右辺は真偽値型→7
- 右辺を数値型に変換して再比較
- 右辺「![]」は、「[]」の部分がオブジェクトとみなされtrue、「!」によりfalseと判断
- falseを数値型に変換して0
- 「[] == 0」として再比較
- 右辺が数値型→4
- 左辺を数値化して再比較
- 「[]」を数値化すると0
- 「0 == 0」として再比較
- 同じ型で数値型で同じ数値である→1-C-iii
- return true
※公式リファレンスでは4, 5の記述はどちらかが数値型でもう一方が文字列型の場合について記述されています。しかし実際には一方が数値型だった場合には文字列型かでなくともこの部分を通る場合があります。おそらく「toString()」メソッドが実装されているオブジェクトはこの文脈上の文字列型と判断されるのだろうと思います。
以下の2例がこの考えを実証するサンプルです。
alert(0 == []);
実行結果
true
配列オブジェクトはtoString()メソッドがあり、実行すると空文字が返り、これを数値型に変換すると0であるのでtrueになる。
alert(0 == null);
実行結果
false
nullはそのまま数値型に変換すれば0になる。しかしtoString()メソッドがないため4に該当するとは判断されず、10に遷移しfalseとなる。
2012/10/28 |
|