はじめに
コードを書く上での基本的かつ重要なスキルの一つは、条件分岐を効果的な形で行うことであり、論理演算の理解はその基盤となります。論理演算はプログラミングの基本知識であり、初学者がこれを理解することはプログラミングのスキル向上に貢献します。
この記事では、論理演算を行うための「論理演算子」の使い方に焦点を当て、論理演算の基本的な概念から具体的な例を挙げて解説していきます。真偽値と条件分岐について学んだ方が次に学ぶ内容として、論理演算の理解は最適なタイミングだと思います。
この記事の対象者
- 真偽値について理解している方
- if文の基本構文について理解している方
- プログラミング初学者の方
この記事で学べること
- 論理演算の基本
- 複合的な論理演算
- 論理演算子の使用方法
論理演算子について
論理演算子は条件分岐において複雑な条件式の構築に利用され、論理演算子を利用することで可読性の高い条件式を組み上げることができます。論理演算子には以下の三種類があります。
- ||(OR):論理和演算子
- &&(AND):論理積演算子
- !(NOT):否定演算子
論理和や論理積、否定については次のセクションで解説します。ここでは、「論理演算子を使用しない場合どうなるか」について触れ、論理演算子が便利なものであることを理解するための解説します。
論理演算子を使わない場合
さっそくですが、二つの条件の結果を基に真偽値を求める必要があるとします。例として、以下の結果になるような条件分岐を定義してみましょう。
- 事前準備:条件結果を格納する変数を二つ定義
- 求める結果1:両方の変数がtrueの場合はtrue
- 求める結果2:どちらか一方の変数がfalseの場合はfalse
- 求める結果3:両方の変数がfalseの場合はfalse
以下は上記の条件の実装例です。理解しやすいようにあえて冗長に記述してあります。
let a = true;
let b = false;
if (a) {
if (b) {
// 両方の変数がtrueの場合
console.log(true);
} else {
// 「aがtrue」で「bがfalse」
console.log(false);
}
} else {
if (b) {
// 「aがfalse」で「bがtrue」
console.log(false);
} else {
// 両方の変数がfalseの場合
console.log(false);
}
}
上記の例は変数が真偽値なので簡単に理解できますが、実際の開発では変数に格納するものが関数や文字列、数値などさまざまなデータであり、「if文の入れ子が必要以上にある」などの可読性を損なう記述はストレスを感じてしまいます。
条件分岐が期待通りの結果にならない場合、if文の条件式や構造を確認しないといけないので、可読性を意識したコーディングを常に意識する必要があります。
論理演算子を使う場合
条件分岐においては、論理演算子が可読性の向上に大きく貢献します。例を挙げると、前述のコードは論理演算子を使用して以下のように書き直すことができます。
let a = true;
let b = false;
if (a && b) {
// 両方の変数がtrueの場合
console.log('true');
} else {
// どちらか一方の変数がfalseまたは
// 両方の変数がfalseの場合
console.log('false');
}
論理演算について初めて学ぶ方にとっては何が起きているのかが分かりにくいかも知れませんが、単純にコードの記述量が少なく、if文の構造もシンプルなので論理演算子を使用するメリットは感じられるかと思います。論理演算子を扱えるようになるため、論理演算の基本知識について学んでいきましょう。
論理演算の基本
プログラミングにおいての演算は、一般的な数値の演算である「四則演算」と、ある事象の真偽を判断する「論理演算」に分類されます。論理演算は複数の真偽値の値を算出し、結果として「trueあるいはfalseを出力」します。
ここでは、論理演算の基本となる論理和、論理積、否定について解説し、JavaScriptでこれらを実装するための方法をご紹介します。
論理和(OR)
論理和は、複数の条件のうち少なくとも一つが満たされていればtrueを返す論理演算です。論理和は「OR」と表現され、「○○または○○」という意味合いを持ちます。以下は真理値表というもので、論理和の結果がどのようになるかを示しています。
| 条件A | 条件B | 結果 |
|---|---|---|
| false | false | false |
| false | true | true |
| true | false | true |
| true | true | true |
JavaScriptで論理和を表現する際は、「||(パイプライン二つ)」を使用します。これを「論理演算子」と言います。コンソールで以下を実行すると、真理値表のとおりに判定されることが確認できます。
false || false; // false
false || true; // true
true || false; // true
true || true; // true
論理演算子は基本的にif文の条件式で使用します。以下は簡単な例です。
let condition1 = true;
let condition2 = false;
if (condition1 || condition2) {
console.log('少なくとも一つの条件が満たされました。');
} else {
console.log('どの条件も満たされませんでした。');
}
// 結果:'少なくとも一つの条件が満たされました。'
上記の例では、condition1がtrueであるため条件式の判定はtrueとなります。
論理積(AND)
論理積は、複数の条件のうち全てがが満たされている場合にtrueを返す論理演算です。論理積は「AND」と表現され、「○○かつ○○」という意味合いを持ちます。以下は論理積の真理値表です。
| 条件A | 条件B | 結果 |
|---|---|---|
| false | false | false |
| false | true | false |
| true | false | false |
| true | true | true |
JavaScriptで論理積を表現する際は、「&&(アンパサンド二つ)」を使用します。前述の「論理演算子について」のセクションのサンプルコードで使用した論理演算子です。コンソールで以下を実行すると、真理値表のとおりに判定されることが確認できます。
false && false; // false
false && true; // false
true && false; // false
true && true; // true
論理積の簡単な例も見ておきましょう。
let condition1 = true;
let condition2 = false;
if (condition1 && condition2) {
console.log('全ての条件が満たされました。');
} else {
console.log('満たされない条件がありました。');
}
// 結果:'満たされない条件がありました。'
上記の例では、condition2がfalseのため条件式の判定がfalseとなり、elseブロック内のコードが実行されます。
否定(NOT)
否定は真偽値の値を反転する論理演算です。「NOT」と表現され、「○○ではない」という意味合いを持ちます。論理和と論理積は複数の条件に対して論理演算を行うのに対し、否定は一つの条件に対して論理演算を行います。以下は否定の真理値表です。
| 条件 | 結果 |
|---|---|
| false | true |
| true | false |
JavaScriptで否定を表現する際は、「!(エクスクラメーション)」を使用します。コンソールで以下を実行すると、真理値表のとおりに判定されることが確認できます。
!true; // false
!false; // true
以下は否定を使用した簡単な例です。
let condition = true;
if (!condition) {
console.log('condition変数はfalseです。');
} else {
console.log('condition変数はtrueです。');
}
// 結果:'condition変数はtrueです。'
上記の例ではconditionの値がtrueのため、否定によって値がfalseに変わり、elseブロック内のコードが実行されます。基本的な論理演算については以上です。
論理演算子の優先順位
ここまででは、2つの条件によるシンプルな論理演算について解説しましたが、論理演算子は通常の算術演算子と同様、一つの式に複数使用することができます。
これにより複雑な条件を簡潔に表現することができますが、この際、論理和と論理積、否定には「算出の優先順位がある」ということに注意が必要です。以下が論理演算子の優先順位です。
- 否定( ! ):最も優先順位が高い
- 論理積( && ):論理和より優先される
- 論理和( || ):最も優先順位が低い
基本的には算術演算子でいうところの優先順位と同じ( 和「+」よりも積「*」が優先される )なので理解しやすいかと思います。また、否定演算子は真偽値の先頭に記述するので、特に優先順位を意識しなくても基本的には問題ないです。
論理演算子の優先順位を理解するために、まずはコードの解析がどのような順番で行われるかを簡単に説明します。コードの解析の順番は以下のように表現できます。
- 一番上の行を見つける
- 行の一番左の文字を見つける
- 左から右へ解析する
- 右に文字が無ければ次の行へ進む
- 2~4を繰り返す
インデントや改行などは人がコードを扱いやすくするためのものであり、厳密には上記の表現は正しいとは言えないですが、要点は得ているので初学者の方には理解しやすいかと思います。
解析順序を基に以下の条件式について考えてみます。
true || false && !true
この条件式の計算を、まずは「演算子に優先順位がない場合」として仮定してみましょう。この場合、まずは最も左側にある論理和「 true || false 」が先に算出されます。
// 左辺「true || false」の結果はtrue
true || false && !true
// つまり以下になります
true && !true // 結果はfalseになるはず
しかし、上記の条件の結果は実際にはtrueになります。これは論理積演算子が論理和演算子よりも優先的に算出されることを示しており、具体的には以下のように算出されます。
// 「false && !true」の結果はfalse
true || false && !true
// つまり以下になります
true || !true // 結果:true
論理積よりも論理和を優先させたい場合は「 () 」を使用します。これも四則演算と同じなので理解しやすいかと思います。
(true || false) && !true
// (true || false)の結果はtrue
true && !true // 結果:false
論理演算子の優先順位についての解説は以上です。続いて、論理演算の基本の応用として、複合的な論理演算について解説します。
複合的な論理演算
論理和や論理積と否定を組み合わせることで、より複雑な条件を定義することができます。複合的な論理演算は実際の開発でも頻繁に利用されるため、これに対する理解が深まると良いです。ここでは複合的な論理演算の基本となる、否定論理和、否定論理積、排他的論理和、否定排他的論理和について解説します。
否定論理和(NOR)
否定論理和は、複数の条件の全てが満たされていないときにtrueを返す論理演算です。否定論理和は「NOR」と表現され、「○○または○○ではない」という意味合いを持ちます。否定論理和の真理値表は以下です。
| 条件A | 条件B | 結果 |
|---|---|---|
| false | false | true |
| false | true | false |
| true | false | false |
| true | true | false |
否定論理和は、論理和を否定することで成立させることができます。コンソールで以下を実行すると真理値表のとおりの結果になります。
!(false || false); // true
!(false || true); // false
!(true || false); // false
!(true || true); // false
否定論理和の注意点として、論理和の条件式を()で囲う必要があります。以下の例は、否定論理和として成立しません。
!false || false; // true
結果こそtrueを返していますが、実際は論理和として論理演算がされているにすぎません。論理和は一つの条件がtrueの場合にtrueと判定されるため、上記の例では!falseがtrueとなるため論理和の演算結果がtrueとなっています。
以下は、否定論理和を使用した簡単な例です。
let condition1 = false;
let condition2 = true;
if (!(condition1 || condition2)) {
console.log('すべての条件がfalseです。');
} else {
console.log('少なくとも一つの条件がtrueです。');
}
// 結果:'少なくとも一つの条件がtrueです。'
上記の例では、condition2がtrueのため否定論理和の演算結果はfalseになり、elseブロック内のコードが実行されます。
否定論理積(NAND)
否定論理積は、複数の条件のうち少なくとも一つが満たされていない場合にtrueを返す論理演算です。否定論理積は「NAND」と表現され、「○○かつ○○ではない」という意味合いを持ちます。否定論理積の真理値表は以下です。
| 条件A | 条件B | 結果 |
|---|---|---|
| false | false | true |
| false | true | true |
| true | false | true |
| true | true | false |
否定論理積は、論理積を否定することで成立させることができます。コンソールで以下を実行すると真理値表のとおりの結果になります。
!(false && false); // true
!(false && true); // true
!(true && false); // true
!(true && true); // false
否定論理積も否定論理和と同様、論理積の条件式を()で囲う必要があります。以下の例は、否定論理積として成立しません。
!false && true; // true
結果こそtrueを返していますが、実際は論理積として論理演算がされているにすぎません。論理積は条件の全てががtrueの場合にtrueと判定されるため、上記の例では!falseがtrueとなるため論理積の演算結果がtrueとなっています。
以下は、否定論理積を使用した簡単な例です。
let condition1 = true;
let condition2 = true;
if (!(condition1 || condition2)) {
console.log('少なくとも一つの条件がfalseです。');
} else {
console.log('すべての条件がtrueです。');
}
// 結果:'少なくとも一つの条件がtrueです。'
上記の例では、条件の全てがtrueのため否定論理積の演算結果はfalseとなり、elseブロック内のコードが実行されます。
排他的論理和(XOR)
排他的論理和についてはあまり使用するケースはないかも知れませんが、複雑な条件を組むための良いトレーニングになるかと思うので解説しておきます。難しく感じる方でも、プログラミングの経験を積むことで今後理解できるようになるかと思うので気にしなくても大丈夫です。
排他的論理和は、二つの条件のうちのどちらかが満たされている場合にtrueを返す論理演算です。論理和との違いとして、両方満たされている場合はfalseとなります。排他的論理和は「XOR」と表現され、「○○または○○で、ただし両方ではない」という意味合いを持ちます。排他的論理和の真理値表は以下です。
| 条件A | 条件B | 結果 |
|---|---|---|
| false | false | false |
| false | true | true |
| true | false | true |
| true | true | false |
排他的論理和の実装は少し複雑になりますが、コンソールで以下を実行すると真理値表と同じ結果が得られます。
let condition1;
let condition2;
condition1 = false;
condition2 = false;
(condition1 || condition2) && !(condition1 && condition2); // false
condition1 = false;
condition2 =true;
(condition1 || condition2) && !(condition1 && condition2); // true
condition1 = true;
condition2 = false;
(condition1 || condition2) && !(condition1 && condition2); // true
condition1 = true;
condition2 = true;
(condition1 || condition2) && !(condition1 && condition2); // false
排他的論理和の条件式について
排他的論理和を実装するための条件式について解説します。この条件式は、論理和と否定論理積の結果を論理積で論理演算することで実装されています。具体的に見てみましょう。
両方がtrueの場合
まずは、二つの条件がtrueの場合で考えてみます。
condition1 = true;
condition2 = true;
(condition1 || condition2) && !(condition1 && condition2);
condition1またはcondition2のどちらか一方でもtrueであれば、左辺の論理和「 (condition1 || condition2) 」はtrueになります。
(true) && !(condition1 && condition2);
condition1とcondition2の両方がtrueの場合は右辺の否定論理積「 !(condition1 && condition2) 」はfalseとなります。
(true) && (false);
最終的に、これらの結果を用いて論理積による論理演算が行われます。
(true) && (false); // false
どちらか一方がfalseだった場合
続いて、どちらか一方がfalseだった場合について考えます。左辺の論理和「 (condition1 || condition2) 」はどちらか一方がfalseであっても、もう一方がtrueであれば演算結果はtrueになります。
condition1 = false;
condition2 = true;
(true) && !(condition1 && condition2);
右辺の否定論理積「!(condition1 && condition2)」は、条件のうち満たされていないものがある場合にtrueを返すので、こちらの演算結果もtrueになります。
左辺と右辺の結果を論理積として論理演算を行うと、両方がtrueなので結果もtrueになります。
(true) && (true); // true
両方がfalseだった場合
最後に、条件の両方がfalseだった場合を考えます。左辺の論理和「 (condition1 || condition2) 」は両方がfalseだった場合はfalseになります。
condition1 = false;
condition2 = false;
(false) && !(condition1 && condition2);;
右辺の否定論理積「!(condition1 && condition2)」は、条件のうち満たされていないものがある場合にtrueを返すので、両方がfalseのときもtrueになります。これらの結果を論理積で論理演算した場合、左辺がfalseなため結果もfalseになります。
(false) && (true); // false
排他的論理和の例
排他的論理和をJavaScriptで再現するための方法として簡単なのは、関数として定義することです。以下は、それを含めた排他的論理和の例です。
// 排他的論理和の関数
function xor(condition1, condition2) {
return (condition1 || condition2) && !(condition1 && condition2);
}
if (xor(true, true)) {
console.log('一方だけがtrueです。');
} else {
console.log('両方falseか、両方trueです。');
}
// 結果:'両方falseか、両方trueです。'
上記の例では、xor()関数の第一引数と第二引数にtrueを渡しています。xor()関数は受け取った引数を利用して排他的論理和による論理演算を行い、結果を戻り値として返しています。
function xor(condition1, condition2) {
return (condition1 || condition2) && !(condition1 && condition2);
}
このxor()関数の戻り値がif文の条件式の結果となります。xor()関数に渡した引数は両方ともtrueなので、排他的論理和の論理演算の結果はfalseとなり、elseブロック内のコードが実行されます。
if (xor(true, true)) {
console.log('一方だけがtrueです。');
} else {
console.log('両方falseか、両方trueです。');
}
// 結果:'両方falseか、両方trueです。
おまけ:否定排他的論理和について
論理演算には他にも否定排他的論理和というものがあります。否定排他的論理和の真理値表は以下です。
| 条件A | 条件B | 結果 |
|---|---|---|
| false | false | true |
| false | true | false |
| true | false | false |
| true | true | true |
否定排他的論理和は、排他的論理和を否定することで再現できます。よって、先ほどの例のxor()関数を使用すると簡単です。
if (!xor(true, true)) {
console.log('両方falseか、両方trueです。');
} else {
console.log('一方だけがtrueです。');
}
// 結果:'両方falseか、両方trueです。'
論理演算子の使用例
実際の開発では、複雑な条件分岐の処理が頻繁に発生します。例えば、ユーザーの種類やアクションによって異なる処理を行いたい場合などです。以下の例で考えてみます。
- 条件1:ユーザーの種類で処理を分岐
- 条件2:ログインしているかどうかで処理を分岐
- 求める結果1:「ログイン中」かつユーザーの種類が「admin」の場合はコンソールに「管理者としてログイン中です。」と出力
- 求める結果2:「ログイン中」かつユーザーの種類が「user」の場合はコンソールに「一般ユーザーとしてログイン中です。」と出力
- 求める結果3:ログイン中でない場合はコンソールに「ログインしていません。」と出力
論理演算子を使用しない場合、以下のような実装になります。
let userType = 'admin'; // ユーザーの種類
let isLoggedIn = true; // ログイン中かどうか
if (!isLoggedIn) {
console.log('ログインしていません。');
} else {
if (userType === 'admin') {
console.log('管理者としてログイン中です。');
} else if (userType === 'user') {
console.log('一般ユーザーとしてログイン中です。');
}
}
// 結果:'管理者としてログイン中です。'
上記のコードは期待どおりの結果になるため問題ありません。しかし、if文が入れ子になっているため可読性が落ち、条件を追加した場合に複雑な構造になっていく可能性があります。
論理演算子を利用することで、これらの条件を効果的に組み上げ、可読性の高いコードを記述することができます。上記のコードを修正すると以下のようになります。
let userType = 'admin';
let isLoggedIn = true;
if (userType === 'admin' && isLoggedIn) {
console.log('管理者としてログイン中です。');
} else if (userType === 'user' && isLoggedIn) {
console.log('一般ユーザーとしてログイン中です。');
} else {
console.log('ログインしていません。');
}
// 結果:'管理者としてログイン中です。'
単純な例ですが、論理演算子を使用することでif文の入れ子を減らすことができています。可読性を意識した方が学習や開発効率が良いので、積極的に論理演算子を使用すると良いと思います。
最後に
この記事では、論理演算の基本的な概念から具体的な例を挙げて解説しました。排他的論理和の実装については少し難解な解説になりましたが、この内容が理解できるようになれば複雑な条件分岐も実装できるようになるかと思います。
条件分岐の処理は、求める結果が得られるのであれば基本的にプログラムとして問題ありません。つまり、同じ処理を実装する場合でも開発者の好みや知識、経験などによって表現が変わります。この記事では論理演算子のメリットについて「可読性を向上させる」ということを強調しましたが、これじゃないとダメというものではなく、「if文を入れ子にした方が分かりやすい場合もある」ということも覚えておくと良いと思います。
プログラミングの制御構造に関する基本要素として、条件分岐以外にもループ処理というものがあります。ループ処理は何らかの条件を基にループを継続するか否かを定義することができます。条件分岐の理解ができた方が次のステップとして学ぶためにオススメです。以下の記事では、JavaScriptでの基本的なループ処理の実装方法について解説しているので、参考にしていただけると幸いです。
