JavaScript勉強会

JavaScriptの学習日記

【JS学習マラソン】第14回 1.2.11 論理演算子

JavaScript学習マラソンの第14回は、

「現代の JavaScript チュートリアル」パート1の2.11「論理演算子」です。

 

論理演算子 https://ja.javascript.info/logical-operators

を読んでみます。

 

条件判定で必要な道具

ifで条件分岐するとき、1つの条件だけでなく、複数の条件を並べて判定する場合がありますね。

 

  • 「1000円以上」の商品:1つの条件で判定
  • 「1000円以上」かつ「5000円以下」の商品:複数の条件で判定

 

そのとき、どのように条件をつなげていくか?を決めるのが「論理演算子」です。

 

JavaScriptには3つの論理演算子があります: || (OR:論理和), && (AND:論理積), ! (NOT:否定)

 

JavaScriptの論理演算子には、

  1. 「&&」 AND  かつ
  2. 「||」  OR  または
  3. 「!」  NOT  ではない

の3つが用意されています。

 

数学でベン図というのを習いましたが、ベン図で書くと関係が分かりやすいです。

 

f:id:jsstudy:20190804090223p:plain

(via https://snowtree-injune.com/2018/08/14/bool/

 

  • 「A and B 」は、AとBの共通部分ですね。
  • 「A or B」は、AとBの合わせた部分です。
  • 「not A」は、A以外の部分です。

 

日常生活の中でも、例えば、いろんな属性(性別、年齢、住所、年収など)を持った人々をグループ分けするときとか、上記3つの判定を組み合わせて使っていますね。

 

短絡評価(最小評価、ショートサーキット評価)

JavaScriptの論理演算子の動作について、1点注意が必要です。

 

2. 短絡評価(最小評価)

オペランドには値だけでなく、任意の式を使用できます。

ORは左から右へ評価、テストをします。

真値に到達したとき、評価はストップし、その値が返却されます。

この処理は左から右にできるだけ短くなるように行われるため、“短絡評価” と呼ばれます。

 

「A or B or C or D or … 」みたいにたくさんの条件を並べた場合、全部の条件を検査していたら、最終的な判定結果を出すまでに時間がかかって、処理が遅くなります。

 

  • ANDの場合、条件が複数あってもどれか1つがfalse(偽)だったら、全体としての答えもfalseになります。
  • ORの場合、条件が複数あってもどれか1つがtrue(真)だったら、全体としての答えもtrueになります。

 

f:id:jsstudy:20190804092954g:plain

(via http://mt-net.vis.ne.jp/ADFE_mail/0489.htm

 

「A or B or C or D or … 」みたいに、ORでたくさんの条件を並べた場合、最初のA(左側)から検査を始めて、途中でtrueが見つかったら、残りの条件は判定する必要がありません

最終的な結論はtrueになることが分かっているので。

 

JavaScriptの論理演算子で条件をたくさん並べた場合、条件を全部チェックしないくても判定結果は分かる=残りの条件は無視される、という動作になってることに注意が必要です。

 

これは、どういう場合に問題になるか?というと、

何かのチェック作業をやらせる関数がたくさんあって、全部やらせた上で最終的な判定結果を得たい場合に、途中でやめられると困る場合があります。

 

「if ( (check_A(x) || check_B(x) || check_C(x) || check_D(x) )」みたいに、条件に式を使った場合、一番最初の(左側の)check_A(x)は必ず実行されるけど、残りは実行されない場合もある、みたいなかんじです。

 

check_A(x)、check_B(x)、check_C(x)、check_D(x)の全部を実行した上で、最終的な判定結果を得たい、という場合は途中で判定処理をやめる短絡評価(最小評価)だと都合が悪いです。

 

ベタな書き方をするなら、

result_A = check_A(x);
result_B = check_B(x);
result_C = check_C(x);
result_D = check_D(x);
if (result_A || result_B || result_C || result_D) {
    result_final = "OK";
} 

 

みたいに書けば、短絡評価を避けることができます。

全部のチェック作業をやらせて、各チェックの判定結果を出しておくことができます。

(result_A、…の部分で1回はチェック作業を通過しています。)

 

短絡評価の性質を積極的に活用する方法 

「||」(OR)の短絡評価(最小評価)の使い方は、トリッキーな書き方?で使われる場合があるので、他人が書いたコードを読む場合には注意が必要でしょう。

 

判定処理を途中でやめる短絡評価の性質を、逆に積極的に活用しているコードも多々あります。

 

下のコードは何を出力するでしょう?

alert( null || 2 || undefined );

答えは 2 で、それが最初の真となる値です。

 

(参考)

numb86-tech.hatenablog.com

 

簡略化を行うべきか

このように、ショートサーキット評価を利用することで、コードを簡略化できる。

だがこれに対しては、批判的な意見も存在する。可読性が落ちるというのが、その理由である。

確かにやり過ぎれば、可読性は落ちるだろう。

だが例えば、先程の複数の論理和演算子などは、むしろ可読性が向上すると思う。

useData = person.address || person.city || person.country;
if(person.address) {
  useData = person.address;
} else if(person.city) {
  useData = person.city;
} else {
  useData = person.country;
};

どちらも同じように動作するが、前者の書き方を知っていると、後者は冗長に感じる。

 

www.webprofessional.jp

 

6.短絡評価

パラメーターがnullや未定義の場合に初期値を代入するコードを6行にわたり書かなくても、短絡評価用に論理演算子を使えば1行で書けます。

■通常

let dbHost;
if (process.env.DB_HOST) {
  dbHost = process.env.DB_HOST;
} else {
  dbHost = 'localhost';
}

■ショートハンド

const dbHost = process.env.DB_HOST || 'localhost';

 

慣れないうちは、短絡評価の積極的な利用は避けた方が無難だと思います。

(最初は面倒でもif文で丁寧に書いた方が間違いが減るかな?)

 

標準演算子と短絡演算子の違い

上記で見た通り、JavaScriptの論理演算子は、短絡評価(最小評価、ショートサーキット評価)の仕組みを採用しています。

 

他のプログラミング言語では、短絡評価の使い分けができる言語もあります。

 

ja.wikipedia.org

 

JavaC#では、

が用意されています。

 

標準演算子がない言語(JavaScriptなど)では、条件を全部評価する標準評価を使いたい場合、条件の並記をやめてif文を入れ子にしたり、上記のように書き方を工夫する必要がありますね。

 

これらに関係する話は「リーダブルコード」という本で解説されています。

9章 変数と読みやすさ

 9.1 変数を削除する

  制御フロー変数を削除する

 

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

 

 

www.oreilly.co.jp

 

まとめ

  • JavaScriptの論理演算子は「&&」「||」「!」の3つ。
  • if文やwhile文などの条件判定の部分で使う。
  • JavaScriptの論理演算子は、短絡評価になっている。
  • 最初は、短絡評価のトリッキーな使い方をするのではなく、普通に条件分岐だけで使えばOK。

 

 

スラスラ読める JavaScript ふりがなプログラミング (ふりがなプログラミングシリーズ)

スラスラ読める JavaScript ふりがなプログラミング (ふりがなプログラミングシリーズ)