論理演算子「論理積(&&)」と「論理和(||)」「論理否定(!)」「Null 合体演算子(??)」について調べました【JavaScript】

JavaScript

JavaScriptの論理演算子について、分かっているようで分からなかったのでメモ。

論理演算子とは

そもそも論理演算子とはなんぞや?ですが、主にif文で使います。
下記のように「&&」「||」「!」を使って条件を判定します。

// True判定されると、コンソールが表示されます

// 論理和(||)
if(1 || null)  { // 左辺または右辺がTrueの場合はTrue判定される
  console.log("条件に合致しました");  //出力される
}

// 論理積(&&)
if(1 && null) { // 左辺と右辺がTrueの場合はTrue判定される
  console.log("条件に合致しました");  //出力されない
}

// 論理否定(!)
if(!(1 && null)) { // Trueの場合False、Falseの場合はTrue判定される
  console.log("条件に合致しました");  //出力される
}

条件式のif文で、どれか1つでも条件に一致していれば実行、全て一致していなければ実行しない。といった使い方をします。

Null 合体演算子とは

Null 合体演算子とは、左辺がnull または undefinedの場合だけ右辺を出力し、それ以外は左辺が出力されます。if文だと次のような使い方ができます。

// Null 合体演算子(??)
if(null ?? 1) { // 
  console.log("条件に合致しました");  //出力される
}

Null 合体演算子は、変数に演算子の結果を格納する時、使用することが多いです。

const result = null ?? "値はnull、またはundefinedです。";
// 変数「result」に"値はnull、またはundefinedです。"が格納される。

const result = "値はnull、undefined以外です。" ?? "値はnull、またはundefinedです。";
// 変数「result」に"値はnull、undefined以外です。"が格納される。

記号の一覧

記号の意味は次の通りです。

論理積&&判定全てがTrueの場合、Trueを返す
論理和||判定の1つでもTrueの場合、Trueを返す
論理否定!実際の判定の逆を返す。
判定がTrueの場合は、False を返し、Falseの場合は、True を返す。
Null 合体演算子??左辺がnull または undefinedの場合だけ、右辺を出力、それ以外は左辺が出力される
True、False判定は出力結果に左右される

True、Falseになる値にはどんなものがあるか

先ほどの条件式では、数字の1がTrue判定されています。
何もないことを表すnullなら何となく分かりますが、数字の1がどうしてTrue判定されるのか、、?
調べたところ、Falseになるのは主に次の値です。これ以外はTrueになると思います。

Falseになる値

  • 0(数字)
  • NaN
  • 空文字
  • null
  • undefind

実際の判定結果をconsole.logに出力しました。判定結果をTrue、Falseで表示させるために(!!)で判定結果を逆の逆にしています。なお、数字の0を厳密に判定するには、Number()メソッドで数値に変換してあげた方が良いらしいです。

console.log("0の判定結果:" + !!(Number(0)));
console.log("NaNの判定結果:" + !!(NaN));
console.log("空文字の判定結果:" + !!(""));
console.log("nullの判定結果:" + !!(null));
console.log("undefinedの判定結果:" + !!(undefined));

See the Pen resultConditionFalse by donguri2020 (@m-ke) on CodePen.

Trueになる値

Falseになる値以外がTrueになりますが、勘違いしそうなものをまとめました。

  • 数字の0以上
  • 空の配列
  • 空のオブジェクト
  • 空でない文字列

こちらの判定結果を確認してみます。

console.log("1の判定結果:" + !!(1));
console.log("空配列の判定結果:" + !!([]));
console.log("空のオブジェクトの判定結果:" + !!({}));
console.log("空でない文字列の判定結果:" + !!("あいうえお"));

実際の判定結果は次のようになります。

See the Pen resultConditionTrue by donguri2020 (@m-ke) on CodePen.

論理積(&&)の挙動について

論理積(&&)は、左辺の値がFalseになったらその時点で値を返し、それ以降の判定は無視されます。
例えば、次の条件式の場合はFalseが返ってきます

10 < 20の判定は無視される

上記は条件式の判定を比較演算の結果にしています。この場合、結果はFalseになります。
この条件式を変数に格納すると、結果的にはfalseが格納され、if文で条件判定すると、結果はFlaseになることが確認できます。

const conditions = 10 < 0 && 10 < 20; //変数にfalseが格納される
if(conditions) {
    return "Trueでした"; // 無視される
  } else if(!conditions) {
    return "Falseでした"; // 返却される
  }

次は、先ほどのように比較演算でなく、値を条件式に指定した場合です。
左辺の値がTrueだと、右辺の値が返却されます。False判定された値がそのまま返却されます。

falseである空の文字が返却される

この場合、変数「conditions」には空文字が格納され、if文の判定はFalseになります。

const conditions = "テスト" && ""; //変数に空文字が格納される
if(conditions) {
    return "Trueでした"; // 無視される
  } else if(!conditions) {
    return "Falseでした"; // 返却される
  }

条件式の数が増えても同様で、左から順番に判定して、Falseになった時点でその値を返却し、それ以降の判定は無視されます。

null以降の条件式は無視される
const conditions = 10 && null && 20; //変数にnullが格納される
if(conditions) {
    return "Trueでした"; // 無視される
  } else if(!conditions) {
    return "Falseでした"; // 返却される
  }

判定が全てTrueになった場合、一番右側の値が返却されます。

この場合、一番右側の20が返却されるので条件判定はTrueになります。

const conditions = 10 && 15 && 20; //変数に20が格納される
if(conditions) {
    return "Trueでした";  // 返却される
  } else if(!conditions) {
    return "Falseでした"; // 無視される
  }

実際の判定結果はこちらで確認できます!

See the Pen && by donguri2020 (@m-ke) on CodePen.

論理和(||)の挙動について

論理和(||)は論理積と逆で、左辺の値がTrueになったらその時点で値を返し、それ以降の判定は無視されます。
例えば、次の条件式の場合はTrueが返ってきます。

10 < 0の判定は無視される

上記の条件式も判定を比較演算の結果にしています。この場合、結果はTrueになります。
この条件式を変数に格納すると、結果的にはtrueが格納され、if文で条件判定すると、結果はTrueになることが確認できます。

const conditions = 10 < 20 || 10 < 0; //変数にtrueが格納される
if(conditions) {
    return "Trueでした"; // 返却される
  } else if(!conditions) {
    return "Falseでした"; // 無視される
  }

次は、先ほどのように比較演算でなく、値を条件式に指定した場合です。
左辺の値がFalseだと、右辺の値が返却されます。

Trueである”てすと”の文字列が返却される

この場合、変数「conditions」には「てすと」の文字列が格納され、if文の判定はTrueになります。

const conditions = "" || "てすと"; //変数に「てすと」の文字列が格納される
if(conditions) {
    return "Trueでした"; // 返却される
  } else if(!conditions) {
    return "Falseでした"; // 無視される
  }

条件式の数が増えても同様で、左から順番に判定して、Trueになった時点でその値を返却し、それ以降の判定は無視されます。

10以降の条件式は無視される
const conditions = null || 10 || 0; //変数に10が格納される
if(conditions) {
    return "Trueでした";  // 返却される
  } else if(!conditions) {
    return "Falseでした"; // 無視される
  }

判定が全てFalseになった場合、一番右側の値が返却されます。

この場合、返却される値が0なので、条件判定はFalse になります。

const conditions = null || 0 || 0; //変数に0が格納される
if(conditions) {
    return "Trueでした";  // 無視される
  } else if(!conditions) {
    return "Falseでした"; // 返却される
  }

実際の判定結果はこちらで確認できます!

See the Pen JavaScriptOR by donguri2020 (@m-ke) on CodePen.

論理和(||)で初期値を設定する

論理和(||)で時々見かける使い方についてメモしておきます。
例えば、以下のように挨拶を返す関数があるとして、引数greetingの値がない場合、初期値を決めておきたい!とします。

ポイントは色付けしている変数greetingTextに代入している論理和(||)です。

// 挨拶を返す関数
function fc(name, greeting) {
  // 引数greetingに値がなければ「こんにちは」が変数に格納される
  const greetingText = greeting || "こんにちは";
  return `${greetingText}。${name}さん`;
}
console.log(fc("マイク", "ハロー")); // ハロー。マイクさん
console.log(fc("花子")); // こんにちは。花子さん

論理和(||)を使えば、引数greetingに値があれば引数の値が変数に格納され、値がない場合はFalse判定となるので、右側の値「こんにちは」が変数に格納されることになります。

if文で判定することもできますが、論理和(||)を使うことでスッキリ記述することができます!

注意点は、False判定される0を引数にすると挙動が想定した通りにならないことです。

Null 合体演算子(??)の挙動について

Null 合体演算子(??)は、左辺がnull または undefinedの場合だけ右辺を返却します。左辺の値が、null または undefined以外の場合は左辺を返却します。

以下の場合、左辺の値がnullなので、右辺の値(正の数字20)が返却されます。

論理和(||)との違い

論理和(||)の挙動と少し似ていますが、論理和は、左辺の値がFalseの場合、右辺の値を返却します。
False判定されるのは、null、undefined以外に0(数字)やNaN、空文字も含まれます。
論理和はこれらの値が左辺にある場合、右辺の値を返却します。

Null 合体演算子(??)はnull または undefinedの場合だけ右辺の値を返却します。
以下の場合、左辺は0(数字)でFalseですが、右辺ではなく、左辺の値0(数字)が返却されます。

論理否定(!)の挙動について

論理否定(!)は実際の判定の逆を返します。
判定がTrueの場合はFalse を返し、Falseの場合はTrue を返します。

判定の逆を返すので、スイッチのような動きを実装したい時によく使います。
簡単なサンプルを作りました。

See the Pen CountUp by donguri2020 (@m-ke) on CodePen.

ボタンをクリックするとカウントアップし、3か15の倍数の時にスイッチがオンになります。
スイッチのオンオフの部分だけ抜き出したコードがこちらです。

const countUpBtn = document.getElementById("countUpBtn");
const icon = document.getElementById("icon");
let flag = false; // オンオフ判定のフラグ

// スイッチオンオプ
const showIcon = (flag) => {
  if(flag) {
    icon.innerHTML = '<i class="fas fa-toggle-on"></i>';
  } else {
    icon.innerHTML = '<i class="fas fa-toggle-off"></i>';
  }
}

// ボタンクリック
countUpBtn.addEventListener('click', () => {
  showIcon(flag);
  if(addNum % 15 == 0) {
      showIcon(!flag);
   } else if(addNum % 3 == 0) {
      showIcon(!flag);
   } else if(addNum % 5 == 0) {
      showIcon(!flag);
    }
});

さらに細かくみていきます。まずオンオフを判定する変数を設定します。
初期値はFalseです。

// オンオフ判定のフラグ
let flag = false; 

スイッチのオンオフの切り替えをする関数showIconを作成します。
引数flagの値がTrueならオンにしてFalseならオフにします。

// スイッチオンオプ
const showIcon = (flag) => {
  if(flag) {
    icon.innerHTML = '<i class="fas fa-toggle-on"></i>';
  } else {
    icon.innerHTML = '<i class="fas fa-toggle-off"></i>';
  }
}

カウントアップのボタンをクリックした時、スイッチのオンオフの切り替えをする関数showIconを実行しますが、引数のflagを論理否定(!)で渡すと、現状のflagの逆の状態を渡すことになります。結果的にオンオフが実装できます。

// ボタンクリック
countUpBtn.addEventListener('click', () => {
  showIcon(flag); // 該当しない数字の場合False
  if(addNum % 15 == 0) {
      showIcon(!flag); // Falseの反対Trueを引数で渡す
   } else if(addNum % 3 == 0) {
       showIcon(!flag); // Falseの反対Trueを引数で渡す
   } else if(addNum % 5 == 0) {
       showIcon(!flag); // Falseの反対Trueを引数で渡す
    }
});

まとめ

なんとなく使っていた論理演算子を改めてまとめました。
基礎中の基礎とはいえ、意外と分かっていない部分もあったのでスッキリしました。

特に変数の代入ではコードがスッキリかけます。今後も積極的に使っていきたいと思います!

コメント