JavaScriptでは、undefined
の大小比較の結果は常にfalse
です。
undefined > 0 // false
undefined >= 0 // false
undefined < 0 // false
undefined <= 0 // false
undefined
同士の大小比較でも常にfalseです。
undefined > undefined // false
undefined >= undefined // false
undefined < undefined // false
undefined <= undefined // false
なぜなのか、仕様を確認してみましょう。
大小比較 共通手順
大小比較のアルゴリズムは、Abstract Relational Comparisonの章に記載があります。
x < y
はtrue
、false
またはundefined
を返します。undefined
が返る時は、少なくとも片方がNaN
(非数)であることを表します。
x < y
の判定のうち、片方(または両方)がundefined
のときのステップを中心に、以下に記載します。
-
x
をプリミティブ型(Boolean
,Null
,Undefined
,Number
,BigInt
,String
,Symbol
のいずれか)に変換する -
y
をプリミティブ型(Boolean
,Null
,Undefined
,Number
,BigInt
,String
,Symbol
のいずれか)に変換する - 変換した結果、両方ともStringであれば、
-
x
とy
を辞書順で並べ、x
の方が先に来るならばtrue
、そうでないならばfalse
を返す(詳しくは仕様を参照してください)
-
- それ以外であれば、
-
x
をさらにNumber
に変換する -
y
をさらにNumber
に変換する -
x
が``NaNであれば
undefined`を返す -
y
が``NaNであれば
undefined`を返す -
x
とy
を数値として比較し、x
の方が小さければtrue
、そうでないならばfalse
を返す(詳しくは仕様を参照してください)
-
undefinedの大小比較 共通手順を追う
例として、undefined < 0
のときの処理を追ってみましょう。
上の手順に当てはめると、x = undefined
、y = 0
です。
-
x
をプリミティブ型(Boolean
,Null
,Undefined
,Number
,BigInt
,String
,Symbol
のいずれか)に変換する
→undefined
をプリミティブ型に変換するとundefined
(変化なし)です。 -
y
をプリミティブ型(Boolean
,Null
,Undefined
,Number
,BigInt
,String
,Symbol
のいずれか)に変換する
→0
をプリミティブ型に変換すると0
(変化なし)です。 - 変換した結果、両方ともStringであれば、
→ 条件に当てはまらないので次に進みます - それ以外であれば、
-
x
をさらにNumber
に変換する -
y
をさらにNumber
に変換する
→Number
への変換表はこちらです。undefined
はNaN
に変換され、0
は0
のままです。
-
データ型 | 返却値 |
---|---|
Undefined | NaN |
Null | +0 |
Boolean | trueならば1、falseならば+0 |
Number | 元の値 |
String | 文字列が数字ならばその数字、それ以外はNaN 。詳細はToNumber Applied to the String Typeを参照 |
Symbol | TypeError exceptionを投げる |
null
やtrue
、false
が数値に変換されるのも興味深いです。これらに言及した記事を参考資料としてリンクしました。
次に、 3. x
がNaN
であればundefined
を返す
→ x
の値を変換した結果がNaN
なので、undefined
が返されます。
さて、ここまででundefined < 0
の評価値はundefined
であることがわかりました。
しかし、実際はundefined < 0
の評価結果はfalse
です。何が間違っているのでしょうか。
それを解き明かすには、もうひとつの仕様を読む必要があります。
大小比較の実行手順
大小比較の実行手順はRuntime Semantics: Evaluationに記載があります。
主要な部分だけ抜粋します。
x < y
の評価方法は、
- 大小比較 共通手順で
x < y
を評価する - 結果が
undefined
であればfalse
、それ以外であれば評価結果を返す
x > y
の評価方法は、
- 大小比較 共通手順で
y < x
を評価する - 結果が
undefined
であればfalse
、それ以外であれば評価結果を返す
x <= y
の評価方法は、
- 大小比較 共通手順で
y < x
を評価する - 結果が
true
またはundefined
であればfalse
、それ以外であればtrue
を返す
x >= y
の評価方法は、
- 大小比較 共通手順で
x < y
を評価する - 結果が
true
またはundefined
であればfalse
、それ以外であればtrue
を返す
undefinedの大小比較の実行手順を追う
undefined < 0
のときの処理を追ってみましょう。
x < y
の評価方法を見ます。
- 大小比較 共通手順で
x < y
を評価する
→ 上で確認したように、undefined < 0
の評価結果はundefined
です。 - 結果が
undefined
であればfalse
、それ以外であれば評価結果を返す
→undefined
なので、false
が返ります。
x > y
、x <= y
、x >= y
のそれぞれについても、undefined < 0
の結果がundefined
なので、全ての比較においてfalse
が返ることがわかりました。
x < y
がfalse
だからといって、x >= y
が必ずしもtrue
にならないことがあるのですね。
参考資料
- Relational Operators
- Abstract Relational Comparison
- JavaScriptの大小比較は数値に変換される - Qiita
- JavaScriptのプリミティブへの変換を完全に理解する - Qiita
- Nullの奇妙な比較、あるいはJavaScriptの仕様を読むことが重要な理由 - Qiita
あとがき
意外にも、undefined
の大小比較についての記載が見当たらず苦労しました。
数値同士や文字列同士以外を比較するようなコードを、実際に仕事で書くことがあるとしたら多分アプリの設計ミスなのですが、undefined
が紛れ込むことはあるかなーと思い、気をつけようと思いました。