2021年8月24日

比較

私たちは数学にある多くの比較演算子を知っています。:

JavaScript では、次のような記述します:

  • より大きい/より小さい: a > b, a < b
  • 大きい/小さいまたは等しい: a >= b, a <= b.
  • 等位チェックは a == b として書かれます(2重の等式記号 '=' に注意してください。1つの記号 a = b は代入を意味します。)
  • 等しくない。数学において、この記法は です。JavaScriptにおいては、感嘆符がその前についた代入として書かれます: a != b.

この記事では、異なる比較のタイプに関して、JavaScript ではどうやるか、またその重要な特性について詳しく学んでいきます。

記事の末尾には “JavaScriptの癖” に関連する問題を回避するための良いレシピがあります。

Boolean は結果です

すべての比較演算子はブール値を返します:

  • true – “はい”, “正しい” もしくは “真” を意味します.
  • false – “いいえ”, “誤り” もしくは “偽” を意味します.

例:

alert( 2 > 1 );  // true (正しい)
alert( 2 == 1 ); // false (誤り)
alert( 2 != 1 ); // true (正しい)

任意の値のように、比較結果は変数に代入することができます:

let result = 5 > 4; // 比較の結果を代入
alert( result ); // true

文字列比較

どちらの文字列がより大きいかを見る場合、いわゆる “辞書” もしくは “数学における辞書式順序” の順序が使われます。

言い換えると、文字列は文字単位で比較されます。

例:

alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true

2つの文字列を比較するアルゴリズムはシンプルです:

  1. 両方の文字列の最初の文字を比較します。
  2. 1つ目のほうが大きい(もしくは小さい)場合、1つ目の文字列は2つ目の文字列よりも大きい(もしくは小さい)です。それで完了です。
  3. そうではなく、もしも最初の文字が等しい場合は、同じ方法で2つ目の文字を比較します。
  4. 文字列の最後までそれを繰り返します。
  5. 両方の文字列が同時に終わった場合、それらは等しいです。そうでなければ長い文字列がより大きいです。

上の例において、比較 'Z' > 'A' は最初のステップで結果を得ます。

文字列 "Glow""Glee" は文字単位の比較がされます。

  1. GG と同じ.
  2. ll と同じ.
  3. oe より大きい. ここでストップ. 1つ目の文字列のほうが大きいです.
実際の辞書ではなく、Unicode順です

上で与えられている比較アルゴリズムは、本の辞書や電話帳で使われているのとおおよそ同じです。しかし全く同じではありません。

例えば、大文字小文字の問題。大文字 "A" は小文字の "a" とは同じではありません。どちらがより大きいでしょう?実際は、小文字 "a" です。なぜでしょう?なぜなら、小文字は内部のエンコーディングテーブル(Unicode)でより大きな値を持っているからです。チャプター 文字列 で具体的な詳細と結果を取り上げます。

異なる型の比較

異なる型に所属している値を比較するとき、それらは数値に変換されます。

例:

alert( '2' > 1 ); // true, 文字列 '2' は数値 2 になります
alert( '01' == 1 ); // true, 文字列 '01' は数値 1 になります

真偽値の場合、true1 になり、 false0 になります。:

例:

alert( true == 1 ); // true
alert( false == 0 ); // true
興味深い結果

次の2つが同時に発生する場合があります:

  • 2つの値が等しい
  • それらの一方は真偽値の true で、もう一方は真偽値の false

例:

let a = 0;
alert( Boolean(a) ); // false

let b = "0";
alert( Boolean(b) ); // true

alert(a == b); // true!

JavaScriptの立場からすると、それは普通です。等価チェックは数値変換を使って変換をします(したがって、"0"0 になります)。一方、 明示的な Boolean 変換は別のルールセットを利用します。

厳密な等価

通常の等価チェック "==" は問題を持っています。0false を異なるものと判断させることはできません:

alert( 0 == false ); // true

空文字列でも同じです:

alert( '' == false ); // true

これは、異なる型のオペランドは等価演算子 == によって数値に変換されるためです。空文字は、ちょうど false のように 0 になります。

もしも 0false を分けたい場合、どうすべきでしょうか?

厳密等価演算子 === は型変換なしで等価をチェックします。

言い換えると、もしも ab が異なる型の場合、a === b はそれらの変換の試みをすることなく、すぐに false を返します。

試してみましょう:

alert( 0 === false ); // false, 型が異なるためです

!= の類似として、“厳密な非等価” 演算子 !== も存在します。

厳密等価チェック演算子は書くのが少し長いですが、起こっていることを明らかにし、エラーの余地を少なくします。

null と undefined の比較

null もしくは undefined が他の値と比較される場合、非直感的な振る舞いになります。

厳密な等価チェック === の場合

それぞれが自身の別々の型に所属しているため、これらの値は異なります。

alert( null === undefined ); // false
非厳密なチェック == の場合

特別なルールがあります。この2つは “スイートカップル” と呼ばれ、(== の意味で)等しくなりますが、これら以外の値とは等しいと扱われることはありません。

alert( null == undefined ); // true
数学や他の比較 < > <= >=

null/undefined は数値に変換されます: null0 になり、undefinedNaN (Not a Number)になります。

今、それらのルールを適用した時に起こる面白いことを見てみましょう。そして、より重要なことはこれらの機能でトラップに陥らない方法です。

奇妙な結果: null vs 0

null とゼロを比較してみましょう:

alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

上の3つの例は数学的には奇妙です。最後の結果は "null はゼロより大きいまたは等しい" ことを述べています。そうであれば上2つの比較のどちらかは正しくなければいけませんが、両方とも false です。

その理由は等価チェック == と比較 > < >= <= は異なった処理するためです。比較は null を数値に変換します、したがって 0 として扱います。そういう訳で (3) null >= 0 は true で、 (1) は false になります。

一方、undefinednull の等価チェック == はいずれの変換もなしにルールによって処理します。それらはお互い等価で他のいずれとも等価ではありません。なので (2) null == 0 は false です。

比べるものがない undefined

undefined は比較に関与しません。:

alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)

なぜそこまでゼロが嫌いなのでしょう?常に false です!

このような結果になった理由は次の通りです:

  • 比較 (1)(2) は、 undefinedNaN に変換されるため false を返します。また、NaN はすべての比較で false を返す特別な数値です。
  • undefinednull とのみ等価で、それ以外とは等価ではないため、等価チェック (3)false を返します。

問題を回避する

なぜこれらの例を見てきたのでしょう?常にこれらの特殊性を覚えておく必要があるでしょうか?そうではありません。実際には、これらのトリッキーなことは徐々に馴染みの深いものになっていくでしょう。ですが、問題を回避するための確実な方法があります。

  • 厳密な等価 === 以外の比較演算子については、例外的な注意を払って undefined/null の比較を行ってください。
  • 本当に正しい場合でない限り、null/undefined かもしれない変数に対して比較 >= > < <= は使ってはいけません。変数がこのような値を持つ可能性がある場合は、それらを別々にチェックしてください。

サマリ

  • 比較演算子は論理値を返します。
  • 文字列は "辞書” 順で、1文字ずつ比較されます。
  • 異なった型の値が比較される場合、それらは数値に変換されます(厳密な等価チェックを除く)
  • nullundefined はそれぞれ等価 == であり、それ以外の値とは等価ではありません。
  • > または < のような比較を、null/undefined になる可能性のある変数に対して使う場合は注意してください。null/undefined を別々にチェックするのが良いアイデアです。

タスク

重要性: 5

式の結果はどうなるでしょう?

5 > 4
"apple" > "pineapple"
"2" > "12"
undefined == null
undefined === null
null == "\n0\n"
null === +"\n0\n"
5 > 4 → true
"apple" > "pineapple" → false
"2" > "12" → true
undefined == null → true
undefined === null → false
null == "\n0\n" → false
null === +"\n0\n" → false

理由:

  1. 明らかに true ですね。
  2. 辞書の比較になるので、false です。
  3. 再び辞書の比較です。"2" の最初の文字は 12 の最初の文字 "1" よりも大きいです。
  4. nullundefined は唯一お互いに等しいです。
  5. 厳密等価は厳密です。両側が異なる型だと false になります。
  6. (4) をみてください。
  7. 異なる型の厳密等価です。
チュートリアルマップ

コメント

コメントをする前に読んでください…
  • 自由に記事への追加や質問を投稿をしたり、それらに回答してください。
  • 数語のコードを挿入するには、<code> タグを使ってください。複数行の場合は <pre> を、10行を超える場合にはサンドボックスを使ってください(plnkr, JSBin, codepen…)。
  • 記事の中で理解できないことがあれば、詳しく説明してください。