133

JavaScriptにC#の&&演算子のような「短絡」評価があるかどうか知りたいのですが。そうでない場合は、採用するのが理にかなっている回避策があるかどうかを知りたいです。

4

3 に答える 3

150

はい、JavaScriptには「短絡」評価があります。

if (true == true || foo.foo){
    // Passes, no errors because foo isn't defined.
}

ライブデモ

if (false && foo.foo){
    // Passes, no errors because foo isn't defined.
}

ライブデモ

于 2012-09-23T17:36:17.600 に答える
48

この回答では、JavaScriptでがどのように機能するかについて詳しく説明し、すべての落とし穴と、演算子の優先順位などの関連するテーマを示します。簡単な定義を探していて、短絡がどのように機能するかをすでに理解している場合は、お勧めします。他の答えをチェックします。


私たち(私たちが思っていた)がこれまでに知っていたこと:

if()まず、ブロック内で、私たち全員がよく知っている動作を調べてみましょう。ここでは、次&&の2つがあるかどうかを確認するために使用しますtrue

if (true && true) {
   console.log('bar');
} 

さて、あなたの最初の本能はおそらく次のように言うことです:'ああ、非常に単純です、コードは両方が次のように評価された場合にステートメントを実行expr1expr2ますtrue'

ええ、はい、いいえ。あなたは技術的に正しいです、それはあなたが説明した振る舞いです、しかしそれはコードが正確に評価される方法ではありません、そして私たちは完全に理解するためにもっと深く掘り下げる必要があります。


とはどの程度正確に&&解釈||されますか?:

エンジンの内部」を見る時が来ました。この実際的な例を考えてみましょう。

function sanitise(x) {
  if (isNaN(x)) {
    return NaN;
  }
  return x;
}

let userinput = 0xFF; // as an example
const res = sanitise(userinput) && userinput + 5

console.log(res);

結果は260..ですが、なぜですか?答えを得るには、短絡評価がどのように機能するかを理解する必要があります。

MDN定義により、 の&&演算子expr1 && expr2は次のように実行されます。

expr1に変換できる場合は、 ;trueを返します。expr2それ以外の場合は、を返しますexpr1

つまり、実際の例では、const resは次のように評価されます。

  1. 呼び出しexpr1-sanitise(0xFF)
  2. 0xFF250の有効な16進数です。それ以外の場合は、NaN
  3. 返された「真実のexpr1」値、実行時間expr2 (そうでない場合NaNは、偽物として停止します)
  4. 真実(数字)なので、userinput付け加えることができ+5ます
  • 「真実」とは、表現が真実であると評価できることを意味します。これが真実偽りの 表現のリストです 。

したがって、ここでは、演算子を使用するだけで、追加のifブロックやさらなるisNaNチェックを回避することができました。&&


それが実際にどのように機能するか:

これまでに、少なくとも演算子がどのように機能するかを理解する必要があります。普遍的なルールは次のとおりです。

  • (some falsy expression) && expr偽りの表現に評価されます
  • (some truthy expression) || expr真実の表現に評価されます

理解を深めるためのその他の例を次に示します。

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() && b() ){
     console.log('foobar'); 
}

//Evaluates a() as false, stops execution.

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() || b() ){
     console.log('foobar'); 
}

/* 1. Evaluates a() as false
   2. So it should execute expr2, which is `b()`
   3. b() returned as true, executing statement `console.log('foobar');`
*/


最後に厄介ですが、非常に重要なこと[Operator Precedence]:

いいですね、うまくいけば、あなたはそれのコツをつかんでいます!最後に知っておく必要があるのは、演算子の優先順位に関するルールです。つまり、次のとおりです。

  • &&オペレーターは常にオペレーターの前に実行されます||

次の例を考えてみましょう。

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log(a() || b() && c());

// returns a() and stops execution

これは、おそらく紛らわしいようにとして返されa()ます。理由は非常に単純です。私たちは左から右に読むことに慣れているので、私たちをだましているのは私たちの視力だけです。console.log()出ていないものを取り出して、純粋に評価に焦点を当てましょう

true || false && false

今、これに頭を包みます:

  1. 演算子が優先されると言った&&ので、最初に評価されます。評価をよりよく想像するのを助けるために、定義を考えてください

    expr1 && expr2
    

    どこ:

    • expr2false
    • expr1true || false
  2. それがトリッキーな部分だったので、今true || false評価されます(expr1-の左側&&)。

    • inがtrueと評価された場合に演算子が実行を停止すると、が||実行され、コードの実行が停止します。expr1 || expr2expr1expr1
  3. 戻り値はtrue

まあ..それはかなりトリッキーでした、すべて奇妙なルールとセマンティクスのために。ただし、数学の場合と同様に()、演算子の優先順位を-でいつでもエスケープできることを忘れないでください

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log((a() || b()) && c());

/* 1. The () escape && operator precedence
   2. a() is evaluated as false, so expr2 (c()) to be executed
   3. c()  
*/

于 2019-05-09T10:23:22.657 に答える
1

論理式は左から右に読み取られ、左の条件の値が合計値を取得するのに十分である場合、右の条件は処理および評価されないという考え方です。いくつかの非常に単純な例:

function test() {
    const caseNumber = document.querySelector('#sel').value;
    const userChoice = () => confirm('Press OK or Cancel');
    if (caseNumber === '1') {
        console.log (1 === 1 || userChoice());
    } else if (caseNumber === '2') {
        console.log (1 === 2 && userChoice());
    } else if (caseNumber === '3') {
        console.log (1 === 2 || userChoice());
    } else if (caseNumber === '4') {
        console.log (1 === 1 && userChoice());
    } else if (caseNumber === '5') {
        console.log (userChoice() || 1 === 1);
    } else if (caseNumber === '6') {
        console.log (userChoice() && 1 === 2);
    }
}
<label for="sel">Select a number of a test case and press "RUN!":</label>
<br><select id="sel">
  <option value="">Unselected</option>
  <option value="1">Case 1</option>
  <option value="2">Case 2</option>
  <option value="3">Case 3</option>
  <option value="4">Case 4</option>
  <option value="5">Case 5</option>
  <option value="6">Case 6</option>
</select>
<button onclick="test()">RUN!</button>

上記の最初の2つのケースは、それぞれコンソールの結果truefalse出力され、左の条件で全体の結果を定義するのに十分であるため、「OK」または「キャンセル」を押すように求めるモーダルウィンドウも表示されません。逆に、ケース3〜6の場合、前者の2つは正しい部分(つまり選択)に依存し、後者の2つは集約されているという事実に関係なく、選択を求めるモーダルウィンドウが表示されます。これらの式の値は、選択内容に依存しません—左の条件が最初に読み取られるためです。したがって、最初に処理する条件に基づいて、条件を左から右に配置することが重要です。

于 2020-11-09T12:19:07.137 に答える