2022年6月5日

論理演算子

JavaScriptには、||(OR)、&&(AND)、!(NOT)、??(Nullish Coalescing)の4つの論理演算子があります。ここでは最初の3つを扱いますが、??演算子は次の記事で説明します。

「論理」と呼ばれていますが、ブール値だけでなく、任意の型の値に適用できます。結果も任意の型になります。

詳細を見ていきましょう。

|| (OR)

「OR」演算子は、2つの縦線記号で表されます。

result = a || b;

古典的なプログラミングでは、論理ORはブール値のみを操作することを目的としています。引数のいずれかがtrueの場合、trueを返し、それ以外の場合はfalseを返します。

JavaScriptでは、演算子は少しトリッキーで、より強力です。しかしまず、ブール値で何が起こるかを見てみましょう。

4つの可能な論理的な組み合わせがあります。

alert( true || true );   // true
alert( false || true );  // true
alert( true || false );  // true
alert( false || false ); // false

ご覧のとおり、結果は両方のオペランドがfalseの場合を除いて常にtrueになります。

オペランドがブール値でない場合、評価のためにブール値に変換されます。

たとえば、数値1trueとして、数値0falseとして扱われます。

if (1 || 0) { // works just like if( true || false )
  alert( 'truthy!' );
}

ほとんどの場合、OR ||if文で使用され、指定された条件のいずれかがtrueかどうかをテストします。

例:

let hour = 9;

if (hour < 10 || hour > 18) {
  alert( 'The office is closed.' );
}

複数の条件を渡すことができます。

let hour = 12;
let isWeekend = true;

if (hour < 10 || hour > 18 || isWeekend) {
  alert( 'The office is closed.' ); // it is the weekend
}

OR "||" は最初の真の値を見つけます

上記のロジックはやや古典的です。それでは、JavaScriptの「追加」機能を取り入れてみましょう。

拡張アルゴリズムは次のとおりです。

複数のORされた値が与えられた場合

result = value1 || value2 || value3;

OR ||演算子は次のことを行います。

  • オペランドを左から右に評価します。
  • 各オペランドについて、ブール値に変換します。結果がtrueの場合、処理を停止し、そのオペランドの元の値を返します。
  • すべてのオペランドが評価された場合(つまり、すべてfalseだった場合)、最後のオペランドを返します。

値は変換なしで元の形式で返されます。

言い換えれば、OR ||の連鎖は、最初の真の値、または真の値が見つからない場合は最後の値を返します。

例:

alert( 1 || 0 ); // 1 (1 is truthy)

alert( null || 1 ); // 1 (1 is the first truthy value)
alert( null || 0 || 1 ); // 1 (the first truthy value)

alert( undefined || null || 0 ); // 0 (all falsy, returns the last value)

これは、「純粋な、古典的な、ブール値のみのOR」と比較して、いくつかの興味深い使用方法につながります。

  1. 変数または式のリストから最初の真の値を取得します。

    たとえば、firstNamelastNamenickNameという変数があり、すべてオプション(つまり、未定義であるか、偽の値を持つ可能性があります)。

    OR ||を使用して、データを持つものを選択し、表示します(何も設定されていない場合は"Anonymous")。

    let firstName = "";
    let lastName = "";
    let nickName = "SuperCoder";
    
    alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder

    すべての変数が偽の場合、「Anonymous」が表示されます。

  2. 短絡評価。

    OR ||演算子のもう1つの機能は、いわゆる「短絡」評価です。

    これは、||が最初の真の値に到達するまで引数を処理し、その値を他の引数に触れることなくすぐに返すことを意味します。

    この機能の重要性は、オペランドが単なる値ではなく、変数の代入や関数の呼び出しなどの副作用を持つ式である場合に明らかになります。

    以下の例では、2番目のメッセージのみが出力されます。

    true || alert("not printed");
    false || alert("printed");

    最初の行では、OR ||演算子はtrueを見た時点ですぐに評価を停止するため、alertは実行されません。

    左側の条件が偽の場合にのみコマンドを実行するために、この機能を使用する人がいます。

&& (AND)

AND演算子は、2つのアンパサンド&&で表されます。

result = a && b;

古典的なプログラミングでは、ANDは両方のオペランドが真の場合にtrueを返し、それ以外の場合はfalseを返します。

alert( true && true );   // true
alert( false && true );  // false
alert( true && false );  // false
alert( false && false ); // false

ifを使用した例:

let hour = 12;
let minute = 30;

if (hour == 12 && minute == 30) {
  alert( 'The time is 12:30' );
}

ORと同様に、任意の値をANDのオペランドとして使用できます。

if (1 && 0) { // evaluated as true && false
  alert( "won't work, because the result is falsy" );
}

AND「&&」は最初の偽の値を見つけます

複数のANDされた値が与えられた場合

result = value1 && value2 && value3;

AND &&演算子は次のことを行います。

  • オペランドを左から右に評価します。
  • 各オペランドについて、ブール値に変換します。結果がfalseの場合、処理を停止し、そのオペランドの元の値を返します。
  • すべてのオペランドが評価された場合(つまり、すべて真だった場合)、最後のオペランドを返します。

言い換えれば、ANDは最初の偽の値、または偽の値が見つからない場合は最後の値を返します。

上記のルールはORに似ています。違いは、ANDが最初の *偽の* 値を返し、ORが最初の *真の* 値を返すことです。

例:

// if the first operand is truthy,
// AND returns the second operand:
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5

// if the first operand is falsy,
// AND returns it. The second operand is ignored
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0

複数の値を連続して渡すこともできます。最初の偽の値がどのように返されるかを見てください。

alert( 1 && 2 && null && 3 ); // null

すべての値が真の場合、最後の値が返されます。

alert( 1 && 2 && 3 ); // 3, the last one
AND &&の優先順位はOR ||より高いです

AND &&演算子の優先順位はOR ||より高くなっています。

そのため、コードa && b || c && dは、本質的に&&式が括弧で囲まれている場合と同じです。(a && b) || (c && d)

if||または&&で置き換えないでください。

場合によっては、AND &&演算子を「ifを記述するより短い方法」として使用する場合があります。

例:

let x = 1;

(x > 0) && alert( 'Greater than zero!' );

&&の右側の操作は、評価がそれに到達した場合にのみ実行されます。つまり、(x > 0)がtrueの場合のみです。

そのため、基本的に次のアナログがあります。

let x = 1;

if (x > 0) alert( 'Greater than zero!' );

&&を使用するバリアントの方が短くなりますが、ifの方が明確で、少し読みやすくなる傾向があります。そのため、各構成要素をその目的で使用することをお勧めします。ifが必要な場合はifを使用し、ANDが必要な場合は&&を使用します。

! (NOT)

ブールNOT演算子は、感嘆符!で表されます。

構文は非常にシンプルです。

result = !value;

演算子は単一の引数を受け取り、次のことを行います。

  1. オペランドをブール型に変換します:true/false
  2. 逆の値を返します。

例:

alert( !true ); // false
alert( !0 ); // true

二重NOT !!は、値をブール型に変換するために時々使用されます。

alert( !!"non-empty string" ); // true
alert( !!null ); // false

つまり、最初のNOTは値をブール値に変換して逆を返し、2番目のNOTはその逆を再び反転します。最終的には、単純な値からブール値への変換が得られます。

同じことを行うより冗長な方法があります。組み込みのBoolean関数です。

alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false

NOT !の優先順位はすべての論理演算子の中で最も高く、常に&&または||の前に実行されます。

課題

重要度:5

以下のコードは何を出力しますか?

alert( null || 2 || undefined );

答えは2です。これは最初の真の値です。

alert( null || 2 || undefined );
重要度:3

以下のコードは何を出力しますか?

alert( alert(1) || 2 || alert(3) );

解答:最初に1、次に2

alert( alert(1) || 2 || alert(3) );

alertへの呼び出しは値を返しません。言い換えると、undefinedを返します。

  1. 最初のOR ||は、左オペランドalert(1)を評価します。これにより、1を含む最初のメッセージが表示されます。
  2. alertundefinedを返すため、ORは真の値を検索して2番目のオペランドに進みます。
  3. 2番目のオペランド2は真であるため、実行は停止され、2が返されてから外部のアラートによって表示されます。

alert(3)には到達しないため、3はありません。

重要度:5

このコードは何を表示しますか?

alert( 1 && null && 2 );

解答:null。リストの最初の偽の値だからです。

alert(1 && null && 2);
重要度:3

このコードは何を表示しますか?

alert( alert(1) && alert(2) );

解答:1、次にundefined

alert( alert(1) && alert(2) );

alertへの呼び出しはundefinedを返します(メッセージを表示するだけで、意味のある戻り値はありません)。

そのため、&&は左オペランドを評価し(1を出力し)、undefinedは偽の値であるため、すぐに停止します。そして、&&は偽の値を探して返します。つまり、完了です。

重要度:5

結果はどのようになりますか?

alert( null || 2 && 3 || 4 );

解答:3

alert( null || 2 && 3 || 4 );

AND &&の優先順位は||より高いため、先に実行されます。

2 && 3 = 3の結果は、式は次のようになります。

null || 3 || 4

これで結果は最初の真の値になります:3

重要度:3

ageが14から90の間(両端を含む)であることを確認するif条件を記述します。

「包括的」とは、ageが14または90に達することができることを意味します。

if (age >= 14 && age <= 90)
重要度:3

ageが14から90の間(両端を含む)ではないことを確認するif条件を記述します。

2つのバリアントを作成します。1つ目はNOT !を使用し、2つ目は使用しません。

最初のバリアント

if (!(age >= 14 && age <= 90))

2番目のバリアント

if (age < 14 || age > 90)
重要度:5

これらのalertのうち、どれが実行されますか?

if(...)内の式の結果はどのようになりますか?

if (-1 || 0) alert( 'first' );
if (-1 && 0) alert( 'second' );
if (null || -1 && 1) alert( 'third' );

解答:最初と3番目が実行されます。

詳細

// Runs.
// The result of -1 || 0 = -1, truthy
if (-1 || 0) alert( 'first' );

// Doesn't run
// -1 && 0 = 0, falsy
if (-1 && 0) alert( 'second' );

// Executes
// Operator && has a higher precedence than ||
// so -1 && 1 executes first, giving us the chain:
// null || -1 && 1  ->  null || 1  ->  1
if (null || -1 && 1) alert( 'third' );
重要度:3

promptを使用してログインを求めるコードを記述します。

訪問者が「Admin」を入力した場合、パスワードを求めます。入力が空行またはEscの場合は、「キャンセルされました」と表示し、別の文字列の場合は「知りません」と表示します。

パスワードは次のようにチェックされます。

  • 「TheMaster」と等しい場合、「ようこそ!」と表示します。
  • 別の文字列の場合、「パスワードが間違っています」と表示します。
  • 空文字列または入力がキャンセルされた場合、「キャンセルされました」と表示します。

スキーマ

入れ子になったifブロックを使用してください。コード全体の可読性に注意してください。

ヒント:プロンプトに空の入力を渡すと、空文字列''が返されます。ESCキーをプロンプト中に押すとnullが返されます。

デモの実行

let userName = prompt("Who's there?", '');

if (userName === 'Admin') {

  let pass = prompt('Password?', '');

  if (pass === 'TheMaster') {
    alert( 'Welcome!' );
  } else if (pass === '' || pass === null) {
    alert( 'Canceled' );
  } else {
    alert( 'Wrong password' );
  }

} else if (userName === '' || userName === null) {
  alert( 'Canceled' );
} else {
  alert( "I don't know you" );
}

ifブロック内の垂直方向のインデントに注意してください。技術的には必須ではありませんが、コードの可読性を向上させます。

チュートリアルマップ