2021年10月1日

比較

数学で多くの比較演算子を学びました。

JavaScriptでは、これらは次のように記述されます。

  • より大きい/より小さい: a > b, a < b
  • より大きい/より小さいまたは等しい: a >= b, a <= b
  • 等しい: a == b, 等しいかどうかのテストは二重の等号 == で行うことに注意してください。一方、単一の a = b は代入を意味します。
  • 等しくない: 数学では と表記しますが、JavaScript では a != b と記述します。

この記事では、さまざまな種類の比較について、JavaScript がどのように行うか、重要な特徴を含めて詳しく学びます。

最後に、「JavaScript の癖」に関連する問題を回避するための良いレシピを見つけることができます。

真偽値が結果となる

すべての比較演算子は真偽値を返します。

  • true – 「はい」、「正しい」、「真実」を意味します。
  • false – 「いいえ」、「間違っている」、「真実ではない」を意味します。

例:

alert( 2 > 1 );  // true (correct)
alert( 2 == 1 ); // false (wrong)
alert( 2 != 1 ); // true (correct)

比較結果は、他の値と同様に変数に代入できます。

let result = 5 > 4; // assign the result of the comparison
alert( result ); // true

文字列の比較

文字列が別の文字列より大きいかどうかを確認するために、JavaScript はいわゆる「辞書順」または「辞書式」順序を使用します。

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

例:

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

2つの文字列を比較するアルゴリズムは簡単です。

  1. 両方の文字列の最初の文字を比較します。
  2. 最初の文字列の最初の文字が他の文字列の文字より大きい (または小さい) 場合、最初の文字列は2番目の文字列より大きい (または小さい) ことになります。これで完了です。
  3. それ以外の場合、両方の文字列の最初の文字が同じ場合は、2番目の文字を同じように比較します。
  4. いずれかの文字列の末尾まで繰り返します。
  5. 両方の文字列が同じ長さで終了した場合、それらは等しくなります。それ以外の場合、長い文字列の方が大きくなります。

上記の最初の例では、'Z' > 'A' の比較は最初のステップで結果が出ます。

2番目の比較 'Glow''Glee' は、文字列が文字単位で比較されるため、より多くのステップが必要になります。

  1. GG と同じです。
  2. ll と同じです。
  3. oe より大きいです。ここで終了します。最初の文字列の方が大きいです。
実際の辞書ではなく、Unicode順

上記の比較アルゴリズムは、辞書や電話帳で使用されるアルゴリズムとほぼ同じですが、まったく同じではありません。

たとえば、大文字と小文字は区別されます。大文字 "A" は小文字 "a" と等しくありません。どちらが大きいでしょうか? 小文字の "a" です。なぜでしょうか? 小文字は、JavaScript が使用する内部エンコードテーブル (Unicode) でより大きなインデックスを持っているからです。このことの詳細と結果については、文字列の章で詳しく説明します。

異なる型の比較

異なる型の値を比較する場合、JavaScript は値を数値に変換します。

例:

alert( '2' > 1 ); // true, string '2' becomes a number 2
alert( '01' == 1 ); // true, string '01' becomes a number 1

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

例:

alert( true == 1 ); // true
alert( false == 0 ); // true
面白い結果

同時に次のことが起こる可能性があります。

  • 2つの値が等しい。
  • それらのうちの1つは真偽値として true であり、もう1つは真偽値として 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 と同様に、空の文字列はゼロになります。

0false と区別したい場合はどうすればよいでしょうか?

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

言い換えれば、ab が異なる型の場合、a === b はそれらを変換しようとすることなく、直ちに false を返します。

試してみましょう

alert( 0 === false ); // false, because the types are different

!= に類似した「厳密な不等価」演算子 !== もあります。

厳密な等価演算子は少し長く書く必要がありますが、何が起こっているかを明らかにし、エラーの余地を減らします。

null と undefined の比較

null または undefined が他の値と比較されると、直感に反する動作があります。

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

これらの値は、それぞれが異なる型であるため、異なります。

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

特別なルールがあります。この2つは「甘いカップル」です。互いに等しい (== の意味で) が、他の値には等しくありません。

alert( null == undefined ); // true
数学およびその他の比較 < > <= >= の場合:

null/undefined は数値に変換されます。null0 になり、undefinedNaN になります。

それでは、これらのルールを適用したときに起こる面白いことをいくつか見てみましょう。そして、もっと重要なことですが、それらの罠に陥らない方法を見てみましょう。

奇妙な結果: null vs 0

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

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

数学的には、それは奇妙です。最後の結果は「null はゼロ以上である」と述べているため、上記の比較のいずれかで true である必要がありますが、どちらも false です。

その理由は、等価性チェック == と比較 > < >= <= の動作が異なるためです。比較では、null を数値に変換し、0 として扱います。そのため、(3) null >= 0 は true であり、(1) null > 0 は 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 に変換され、NaN がすべての比較で false を返す特別な数値であるため、false を返します。
  • 等価性チェック (3) は、undefinednullundefined とのみ等しく、他の値とは等しくないため、false を返します。

問題を回避する

なぜこれらの例を検討したのでしょうか? これらの特徴を常に覚えておくべきでしょうか? まあ、そうではありません。実際、これらのトリッキーなことは時間の経過とともに徐々に馴染んでいきますが、それらによる問題を回避するための確実な方法があります。

  • 厳密な等価性 === を除く、undefined/null との比較は例外的な注意を払って処理してください。
  • null/undefined になる可能性のある変数で比較 >= > < <= を使用しないでください。何をしているのか本当に確信している場合を除きます。変数がこれらの値を持つ可能性がある場合は、それらを個別に確認してください。

まとめ

  • 比較演算子は真偽値を返します。
  • 文字列は、「辞書」順で文字単位で比較されます。
  • 異なる型の値が比較されると、数値に変換されます (厳密な等価性チェックを除く)。
  • null および undefined は、互いに == で等しく、他の値とは等しくありません。
  • 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 です。"a""p" より小さいです。
  3. ここでも、辞書順の比較です。最初の文字 "2" は最初の文字 "1" より大きいです。
  4. nullundefined は互いに等しいだけです。
  5. 厳密な等価性は厳密です。両側の型が異なるため、false になります。
  6. (4) と同様に、nullundefined とのみ等しくなります。
  7. 異なる型の厳密な等価性。
チュートリアルマップ

コメント

コメントする前にこれを読んでください…
  • 改善するための提案がある場合は、コメントする代わりに GitHub issue を送信するか、プルリクエストを送信してください。
  • 記事で何か理解できないことがある場合は、詳しく説明してください。
  • コードを数語挿入するには、<code> タグを使用し、複数行の場合は <pre> タグで囲み、10 行を超える場合はサンドボックス (plnkrjsbincodepen…) を使用してください。