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

(1/1)
比較演算子
JavaScriptには、比較演算子と論理演算子がある。比較演算子は、データ型まで厳密に比較を行う厳密等価と厳密不等価が用意されている。
数値の範囲で判断するときには、比較演算子と論理演算子を組み合わせて使う。

目次

サンプル・プログラム

比較演算子:Number型

JavaScriptには、値の大小を比較する比較演算子が用意されている。
比較演算子は a operator b のような式になる2項演算子で、結果は Boolean型で、成立すればtrueを、不成立ならfalseを返す。
イコール1文字 = は代入演算子だったが、2文字 == になると等価演算子となる。
比較演算子
演算子意味
==等価
!=不等価
===厳密等価
!==厳密不等価
>より大きい
>=以上
<より小さい
<=以下
まず、Number型の比較結果を見ていこう。

comp1.html

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

String型 ではUnicodeを用い、標準的な辞書順に基づいて比較が行われる。ここで辞書順というところが曲者で、実際には、String型では大小比較は用いず、等価または不等価のみにとどめた方がいい。

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

イコールが3文字 ===厳密等価演算子と呼び、オペランドの値もデータ型も揃って等しいときにtrueとなる。厳密不等価演算子 !== はその逆だ。

comp3.html

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

"comp3.html" は、数値 123と文字列 '123' を比較するプログラムだ。
2.2 データ型 - 動的型付け」で紹介したように、JavaScriptでは動的型付けが行われるため、等価演算子 123 == '123' はtrueになる。厳密等価演算子を使うとfalseになる。
予期しないバグの温床になるため、JavaScriptで等価比較を行う際は、厳密等価演算子を用いた方が無難である。

論理演算子

これまで見てきたように、IE11はブラウザとしては旧式で、JavaScriptプログラムが期待通りの動きをしない場合がある。そこで、IE11を識別するプログラムを作ってみることにする。
IE10以前では、ユーザーエージェント(navigator.userAgent)に 'MEIE' という文字列が含まれている。IE11では、これが 'Trident' という文字列に替わる。
これをプログラムにしたものが "logic1.html" である。

logic1.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     let ua = navigator.userAgent.toUpperCase();     //大文字変換
  23:     let res;                                        //判定結果
  24: 
  25:     //ユーザーエージェントで判定
  26:     if (ua.indexOf('MSIE'> -1) {
  27:         res = 'IEです';
  28:     } else if (ua.indexOf('TRIDENT'> -1) {
  29:         res = 'IEです';
  30:     } else {
  31:         res = 'IEではありません';
  32:     }
  33: 
  34:     //結果表示
  35:     document.getElementById('res').innerHTML = res;
  36: }
  37: </script>

toUpperCase() は文字列を大文字にするメソッド。indexOf() は、文字列に指定した部分文字列を含むかどうかを調べるメソッドである。部分文字列がなければ -1 が返る。
これを、あとで説明するif~else if~else文を使って場合分け判別している。
ただ、1つめのif文と、2つめのelse if文は、いずれも「IEである」場合だ。これを1つにまとめた方が、プログラムが短くなるし、バグを減らす効果もある。

こういうときに使うのが論理演算子である。
2つ以上の式がすべて成り立つか(論理積)、いずれか1つ以上が成り立つか(論理和)、1つも成り立たないか(論理否定)の3種類がある。
論理演算子
演算子意味
&&論理積(AND)
||論理和(OR)
!論理否定(NOT)

logic2.html

  19: <script>
  20: //ページのロード時に実行
  21: window.onload = function() {
  22:     let ua = navigator.userAgent.toUpperCase();     //大文字変換
  23:     let res;                                        //判定結果
  24: 
  25:     //ユーザーエージェントで判定
  26:     if ((ua.indexOf('MSIE'> -1|| (ua.indexOf('TRIDENT'> -1)) {
  27:         res = 'IEです';
  28:     } else {
  29:         res = 'IEではありません';
  30:     }
  31: 
  32:     //結果表示
  33:     document.getElementById('res').innerHTML = res;
  34: }
  35: </script>

"logic2.html" は論理積を使って、IEである条件を1つの式にまとめたものだ。

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

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

comp4.html

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

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

comp5.html

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

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

このときの論理積(AND)と論理和(OR)の関係を表したのが下の数直線である。
AND条件とOR条件
AND条件とOR条件

コラム:集合と論理

かつて中学の数学の学習範囲だった「集合と論理」は高校の数学I(または数学A)に移動した。義務教育の範囲では、比較演算子と論理演算子の組み合わせができないというのは困ったものである。
ここでは、真理値表とベン図を掲載する。どうか高校数学の参考書の該当箇所を併読いただきたい。
真理値表
真理値表
ベン図
ベン図

コラム:falsyとtruthy

本文で論理演算子を紹介したが、要するに、論理積(&&)すべてのオペランドが true の時に成立し、論理和(||)はいずれか1つのオペランドが true の時に成立する。
ここで、オペランドに暗黙の型変換厳密不等価が含まれる場合に false となる falsy なデータは8つしかないので、これを下表に整理する。
falsy 以外のデータは true になる(truthy)。
falsyになるデータ
No.備  考
1falseBoolean基本
20NumberNumber型のゼロ
3-0Number数値のゼロに等しい
40nBigIntBigInt型のゼロ
5""String空文字列
6nullnull何もない
7undefinedundefined未定義
8NaN-数値ではない

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

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

コラム:デフォルト引数

この短絡評価の性質を利用し、引数がないときにデフォルト値を設定することができる。

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').innerHTML = y;
  33:     // 引数を指定しないで関数実行
  34:     y = hoge1();
  35:     document.getElementById('ret2').innerHTML = y;
  36: }
  37: </script>

関数 hoge(x) の冒頭にある論理和 x || 99 だが、x に値が入っていると truthy として評価され、x そのものが返る。引数を指定しないと x は undefined となるから、falsy として評価され、99 が返る。
ただし、引数として 0 を指定すると、x が falsy となってしまい、99が返ることになる。この点は注意が必要だ。

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').innerHTML = y;
  32:     // 引数を指定しないで関数実行
  33:     y = hoge2();
  34:     document.getElementById('ret2').innerHTML = y;
  35: }
  36: </script>

JavaScript ES6ではデフォルト引数が導入された。
関数宣言時に
function 関数名(引数1=デフォルト値1, 引数2=デフォルト値2,...) {
}
のように書くことで、引数が省略されたときにデフォルト値が代入される。
デフォルト引数を使うと、引数 x にゼロを代入しても、正しい値が戻される。

練習問題

(この項おわり)
header