2.6 比較演算子と論理演算子

(1/1)
金髪ツインテールの女性が比較演算子の式を書いたボードを持つ
比較演算子を使った式
JavaScriptでは、2つの値が等しいか、どちらが大きいかを比較演算子で調べる。複数の条件を組み合わせるときは論理演算子を使う。本稿では、データ型も含めて比較する厳密等価、数値の範囲判定、文字列比較、短絡評価などを、実行できる例とともに説明する。

目次

サンプル・プログラム

比較演算子:Number型

JavaScriptには、値の大小や等しさを調べる比較演算子がある。
比較演算子は a 演算子 b のように2つのオペランドを取る。結果は Boolean型で、関係が成り立てば true、成り立たなければ false を返す。
イコール1文字 = は代入演算子である。2文字 == は型変換を伴う等価演算子、3文字 === は型変換を行わない厳密等価演算子である。
比較演算子
演算子意味
==等価
!=不等価
===厳密等価
!==厳密不等価
>より大きい
>=以上
<より小さい
<=以下
まず、Number型の比較結果を見ていこう。

comp1.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     let a = 3, b = 2;
  23:     let c;
  24:     document.getElementById('ret1').textContent = 'a = ' + a.toString();
  25:     document.getElementById('ret2').textContent = 'b = ' + b.toString();
  26: 
  27:     c = a > b;
  28:     document.getElementById('ret3').textContent = 'a > b ... ' + c.toString();
  29:     c = a < b;
  30:     document.getElementById('ret4').textContent = 'a < b ... ' + c.toString();
  31:     c = a == b;
  32:     document.getElementById('ret5').textContent = 'a == b ... ' + c.toString();
  33:     c = a !b;
  34:     document.getElementById('ret6').textContent = 'a != b ... ' + c.toString();
  35:     c = a >b;
  36:     document.getElementById('ret7').textContent = 'a >= b ... ' + c.toString();
  37:     c = a <b;
  38:     document.getElementById('ret8').textContent = 'a <= b ... ' + c.toString();
  39: }
  40: </script>

比較演算子:String型

次に、String型の比較結果を見ていこう。

comp2.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     let a = 'abc', b = 'abd';
  23:     let c;
  24:     document.getElementById('ret1').textContent = 'a = ' + a.toString();
  25:     document.getElementById('ret2').textContent = 'b = ' + b.toString();
  26: 
  27:     c = a > b;
  28:     document.getElementById('ret3').textContent = 'a > b ... ' + c.toString();
  29:     c = a < b;
  30:     document.getElementById('ret4').textContent = 'a < b ... ' + c.toString();
  31:     c = a == b;
  32:     document.getElementById('ret5').textContent = 'a == b ... ' + c.toString();
  33:     c = a !b;
  34:     document.getElementById('ret6').textContent = 'a != b ... ' + c.toString();
  35:     c = a >b;
  36:     document.getElementById('ret7').textContent = 'a >= b ... ' + c.toString();
  37:     c = a <b;
  38:     document.getElementById('ret8').textContent = 'a <= b ... ' + c.toString();
  39: }
  40: </script>

String型 の大小比較は、基本的にUTF-16コード単位の並びを先頭から比べる。自然な日本語の五十音順や、人が期待する辞書順とは一致しないことがある。言語に合った並べ替えには Intl.CollatorlocaleCompare() を使う。

比較演算子:厳密等価と厳密不等価

イコール3文字の ===厳密等価演算子で、暗黙の型変換をせずに2つの値を比較する。型が異なれば false となり、同じ型なら、その型の規則に従って比較する。厳密不等価演算子 !== は厳密等価の結果を反転する。

comp3.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     let a = 123, b = '123';
  23:     let c;
  24:     document.getElementById('ret1').textContent = 'a = ' + a.toString() + '...' + typeof a;
  25:     document.getElementById('ret2').textContent = 'b = ' + b.toString() + '...' + typeof b;
  26: 
  27:     c = a > b;
  28:     document.getElementById('ret3').textContent = 'a > b ... ' + c.toString();
  29:     c = a < b;
  30:     document.getElementById('ret4').textContent = 'a < b ... ' + c.toString();
  31:     c = a == b;
  32:     document.getElementById('ret5').textContent = 'a == b ... ' + c.toString();
  33:     c = a !b;
  34:     document.getElementById('ret6').textContent = 'a != b ... ' + c.toString();
  35:     c = a === b;
  36:     document.getElementById('ret7').textContent = 'a === b ... ' + c.toString();
  37:     c = a !== b;
  38:     document.getElementById('ret8').textContent = 'a !== b ... ' + c.toString();
  39: }
  40: </script>

"comp3.html" は、数値 123 と文字列 '123' を比較するプログラムである。
等価演算子 == は型が違う値を一定の規則で変換してから比較するため、123 == '123'true になる。一方、厳密等価演算子では型変換を行わないので、123 === '123'false である。意図しない型変換を避けるため、通常は ===!== を使うと分かりやすい。

例外として、NaN === NaNfalse になる。NaN かどうかは Number.isNaN() で調べる。また、オブジェクト同士は内容が似ていても、同じオブジェクトを参照している場合だけ ===true になる。

論理演算子

論理演算子は、条件を組み合わせたり、真偽を反転したりする。&& は左辺と右辺がともにtruthyのとき、|| は少なくとも一方がtruthyのときに成立する。! はtruthyとfalsyを反転し、必ずBoolean型の値を返す。
"logic1.html" は、Boolean型の値を使って3種類の論理演算子の結果を表示する。

logic1.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     const a = true;
  23:     const b = false;
  24: 
  25:     document.getElementById('ret1').textContent = 'a = ' + a.toString();
  26:     document.getElementById('ret2').textContent = 'b = ' + b.toString();
  27:     document.getElementById('ret3').textContent = 'a && b ... ' + (a && b).toString();
  28:     document.getElementById('ret4').textContent = 'a || b ... ' + (a || b).toString();
  29:     document.getElementById('ret5').textContent = '!a ... ' + (!a).toString();
  30: }
  31: </script>

Boolean型の値だけを使う場合、true && falsefalsetrue || falsetrue!truefalse になる。数値や文字列などを使った場合の戻り値は、後の「比較演算子や論理演算子が返す値」で説明する。

論理演算子には次の3種類がある。
論理演算子
演算子意味
&&論理積(AND)
||論理和(OR)
!論理否定(NOT)

logic2.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     const age = 15;
  23:     const hasGuardianConsent = true;
  24:     const canParticipate = (age >18|| hasGuardianConsent;
  25: 
  26:     document.getElementById('ret1').textContent = '年齢 = ' + age.toString();
  27:     document.getElementById('ret2').textContent = '保護者の同意 = ' + hasGuardianConsent.toString();
  28:     document.getElementById('ret3').textContent = canParticipate ? '参加できます' : '参加できません';
  29: }
  30: </script>

"logic2.html" は、年齢が18歳以上、または保護者の同意があるときに参加できるという条件を、論理和 || で表す。サンプルでは年齢が15歳でも、保護者の同意があるため条件は成立する。

比較演算子と論理演算子の組み合わせ

値の範囲で判断するとき、比較演算子と論理演算子の組み合わせを用いる。
たとえば、1980年代生まれかどうかを判断するプログラムが "comp4.html" である。生年は乱数 Math.random() を使って発生させる。

comp4.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     const year = Math.floor(1950 + Math.random() * 70);
  23:     let result = '';
  24:     document.getElementById('year').textContent = year.toString();
  25: 
  26:     if ((year >1980&& (year <1989)) {
  27:         result = 'です';
  28:     } else {
  29:         result = 'ではありません';
  30:     }
  31:     document.getElementById('ret').textContent = result;
  32: }
  33: </script>

生年を代入した変数 year が1980以上かつ1989以下なら1980年代生まれだと判断する。

comp5.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     const year = Math.floor(1950 + Math.random() * 70);
  23:     let result = '';
  24:     document.getElementById('year').textContent = year.toString();
  25: 
  26:     if ((year < 1980|| (year > 1989)) {
  27:         result = 'ではありません';
  28:     } else {
  29:         result = 'です';
  30:     }
  31:     document.getElementById('ret').textContent = result;
  32: }
  33: </script>

"comp5.html" は逆に、生年を代入した変数 year が1980未満または1989を超えたら1980年代生まれではないと判断する。

「1980以上かつ1989以下」の否定は「1980未満または1989より大きい」になる。この関係を表したのが下の数直線である。
AND条件とOR条件
AND条件とOR条件

コラム:集合と論理

プログラミングの条件式は、数学の集合や命題と深く関係している。たとえば論理積は2つの条件が重なる部分、論理和はどちらか一方でも満たす部分、論理否定は条件を満たさない部分に対応する。
ここでは、truefalse の組み合わせを整理する真理値表と、集合の関係を図で表すベン図を掲載する。
真理値表
真理値表
ベン図
ベン図

コラム:falsyとtruthy

JavaScriptは、if文や論理演算子で値を判定するとき、その値をBoolean型として扱う。false とみなされる値を falsytrue とみなされる値を truthy と呼ぶ。
通常のプログラムで使うfalsyな値は次の8種類であり、それ以外はtruthyである。なお、Webブラウザには互換性のために残された特殊な document.all もfalsyとして扱うという例外がある。
falsyになるデータ
No.備  考
1falseBoolean基本
20NumberNumber型のゼロ
3-0Number数値のゼロに等しい
40nBigIntBigInt型のゼロ
5""String空文字列
6nullnull何もない
7undefinedundefined未定義
8NaNNumber非数を表す特殊な数値

コラム:比較演算子や論理演算子が返す値

比較演算子は、常に true または false を返す。
一方の論理演算子は、論理否定(!)は常に true または false を返すが、論理積(&&)と論理和(||)は、短絡評価により、評価した値そのものを返す。
どういうことかというと、たとえば
a && b
という論理積において、
  • a が falsy なら、a を返す(b は評価しない)
  • a が truthy なら、b を返す
となる。論理和の場合はこの逆で、
a || b
という論理和において、
  • a が truthy なら、a を返す(b は評価しない)
  • a が falsy なら、b を返す
となる。

コラム:デフォルト引数

かつては短絡評価を利用して、引数がないときの代替値を設定する書き方がよく使われた。しかし、現在はデフォルト引数やnull合体演算子を使う方が意図を明確にできる。

defArg1.html

  20: <script>
  21: // ページのロード時に実行
  22: window.onload = function() {
  23:     // 引数が1つの関数定義
  24:     function hoge1(x) {
  25:         x = x || 99;        // デフォルト値 99
  26:         return x;
  27:     }
  28: 
  29:     let y;
  30:     // 引数を指定して関数実行
  31:     y = hoge1(1);
  32:     document.getElementById('ret1').textContent = y;
  33:     // 引数を指定しないで関数実行
  34:     y = hoge1();
  35:     document.getElementById('ret2').textContent = y;
  36:     // 引数に0を指定して関数実行
  37:     y = hoge1(0);
  38:     document.getElementById('ret3').textContent = y;
  39: }
  40: </script>

関数 hoge1(x) の冒頭にある x || 99 は、x がtruthyなら x、falsyなら99を返す。引数を省略すると xundefined なので99になる。
ただし、0、空文字列、falseNaN もfalsyであるため、有効な値として渡しても99に置き換わる。"defArg1.html" は、引数に0を指定した場合も表示して、この問題を確認する。

null または undefined のときだけ代替値を使いたい場合は、null合体演算子 ?? を使い、x ?? 99 と書ける。この場合、x が0や空文字列でも、その値を保つ。

defArg2.html

  20: <script>
  21: // ページのロード時に実行
  22: window.onload = function() {
  23:     // 引数が1つの関数定義
  24:     function hoge2(x = 99) {    // デフォルト引数 99
  25:         return x;
  26:     }
  27: 
  28:     let y;
  29:     // 引数を指定して関数実行
  30:     y = hoge2(0);
  31:     document.getElementById('ret1').textContent = y;
  32:     // 引数を指定しないで関数実行
  33:     y = hoge2();
  34:     document.getElementById('ret2').textContent = y;
  35: }
  36: </script>

ECMAScript 2015(ES2015)ではデフォルト引数が導入された。
関数宣言時に
function 関数名(引数1=デフォルト値1, 引数2=デフォルト値2,...) {
}
のように書くと、引数を省略したとき、または undefined を渡したときにデフォルト値が使われる。null を渡した場合には適用されない。
デフォルト引数を使えば、引数 x に0を渡しても0を保てる。"defArg2.html" では、0と引数省略の両方を実行して違いを確かめる。

練習問題

参考サイト

(この項おわり)
header