ややこしいために、CoffeeScriptからは==が追放されてしまっていますが、==や===はどのような条件で等価になるのでしょうか。なお、これ以降で「仕様書」と書いた部分は、ECMA-262 5.1版のことを指します。
===
===の厳密な定義は仕様書11.9.6にありますが、噛み砕けば以下のようになります。
- Objectの場合は、同じオブジェクトならtrue、そうでなければfalse
- それ以外の文字列、数値、ブール値、null、undefinedは、原則同じ値ならtrue、そうでなければfalse
- 文字列はコードポイントの逐次比較、正規化はされない
- 例外1(数値): +0 === -0
- 例外2(数値): NaN !== NaN
==
==の場合は、以下のような流れです(仕様書11.9.3)。
- 両辺が同じ型(Object、文字列、数値、ブール値、null、undefinedの分類で)なら、===の結果と同じ。
- null == undefined
- 一方が文字列、もう片方が数値なら、文字列を数値に変換して1比較する。
- 片方がブール値なら、
trueを整数の1に、falseを整数の0に変換してから==で比較 - Objectと(文字列または数値)の場合、Objectをプリミティブ値に変換して==で比較
- それ以外の組み合わせではfalseを返す
途中にある「プリミティブ値への変換」ですが、概ね以下のような感じです(仕様書9.1ほか)。
- ラッパーオブジェクト(Boolean、String、Number)…元のプリミティブ値を返す
- JavaScript標準であるオブジェクト…
toString()をした結果 -
valueOf()がプリミティブ値を返すオブジェクト2…そのプリミティブ値
わかりやすく、表にまとめてみました。
| \ | Object | 文字列 | 数値 | ブール値 | null | undefined |
|---|---|---|---|---|---|---|
| Object | === | Objectをプリミティブに変換 | プリミティブ変換 | ブール値は数値に、Objectはプリミティブに変換 | false | false |
| 文字列 | Objectをプリミティブに変換 | === | 文字列を数値へ変換 | 両方数値に変換 | false | false |
| 数値 | Objectをプリミティブに変換 | 文字列を数値へ変換 | === | ブール値を数値に変換 | false | false |
| ブール値 | ブール値は数値に、Objectはプリミティブに変換 | 両方数値に変換 | ブール値を数値に変換 | === | false | false |
| null | false | false | false | false | true | true |
| undefined | false | false | false | false | true | true |
なお、Objectから変換されたプリミティブと比較する相手の型が一致しない場合、さらに変換が行われます。たとえば、以下のような流れです。
new Boolean(true) == true
new Boolean(true) == 1 //1. ブール値が数値に変換される
true == 1 //2. Booleanオブジェクトが.valueOf()経由でプリミティブ値に
1 == 1 //3. ブール値と別の型の比較なので数値に変換
true