JavaScriptにC#の&&演算子のような「短絡」評価があるかどうか知りたいのですが。そうでない場合は、採用するのが理にかなっている回避策があるかどうかを知りたいです。
3 に答える
この回答では、JavaScriptで短絡がどのように機能するかについて詳しく説明し、すべての落とし穴と、演算子の優先順位などの関連するテーマを示します。簡単な定義を探していて、短絡がどのように機能するかをすでに理解している場合は、お勧めします。他の答えをチェックします。
私たち(私たちが思っていた)がこれまでに知っていたこと:
if()
まず、ブロック内で、私たち全員がよく知っている動作を調べてみましょう。ここでは、次&&
の2つがあるかどうかを確認するために使用しますtrue
。
if (true && true) {
console.log('bar');
}
さて、あなたの最初の本能はおそらく次のように言うことです:'ああ、非常に単純です、コードは両方が次のように評価された場合にステートメントを実行expr1
しexpr2
ますtrue
'
ええ、はい、いいえ。あなたは技術的に正しいです、それはあなたが説明した振る舞いです、しかしそれはコードが正確に評価される方法ではありません、そして私たちは完全に理解するためにもっと深く掘り下げる必要があります。
とはどの程度正確に&&
解釈||
されますか?:
「 javascriptエンジンの内部」を見る時が来ました。この実際的な例を考えてみましょう。
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
は次のように評価されます。
- 呼び出し
expr1
-sanitise(0xFF)
0xFF
250の有効な16進数です。それ以外の場合は、NaN
- 返された「真実の
expr1
」値、実行時間expr2
(そうでない場合NaN
は、偽物として停止します) - 真実(数字)なので、
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
今、これに頭を包みます:
演算子が優先されると言った
&&
ので、最初に評価されます。評価をよりよく想像するのを助けるために、定義を考えてくださいexpr1 && expr2
どこ:
expr2
はfalse
expr1
はtrue || false
それがトリッキーな部分だったので、今
true || false
評価されます(expr1
-の左側&&
)。- inがtrueと評価された場合に演算子が実行を停止すると、が
||
実行され、コードの実行が停止します。expr1 || expr2
expr1
expr1
- inがtrueと評価された場合に演算子が実行を停止すると、が
戻り値は
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()
*/
論理式は左から右に読み取られ、左の条件の値が合計値を取得するのに十分である場合、右の条件は処理および評価されないという考え方です。いくつかの非常に単純な例:
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つのケースは、それぞれコンソールの結果true
にfalse
出力され、左の条件で全体の結果を定義するのに十分であるため、「OK」または「キャンセル」を押すように求めるモーダルウィンドウも表示されません。逆に、ケース3〜6の場合、前者の2つは正しい部分(つまり選択)に依存し、後者の2つは集約されているという事実に関係なく、選択を求めるモーダルウィンドウが表示されます。これらの式の値は、選択内容に依存しません—左の条件が最初に読み取られるためです。したがって、最初に処理する条件に基づいて、条件を左から右に配置することが重要です。