简体   繁体   English

JavaScript 有“短路”评估吗?

[英]Does JavaScript have “Short-circuit” evaluation?

I would like to know if JavaScript has "short-circuit" evaluation like && Operator in C#.我想知道 JavaScript 是否有像 C# 中的 && 运算符这样的“短路”评估。 If not, I would like to know if there is a workaround that makes sense to adopt.如果没有,我想知道是否有一种可行的解决方法可以采用。

Yes, JavaScript has "short-circuit" evaluation.是的,JavaScript 有“短路”评估。

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

Live DEMO现场演示

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

Live DEMO现场演示

This answer goes into great detail on how works in JavaScript, with all the gotcha's and also relevant themes such as operator precedence, if you're looking for a quick definition and already understand how short-circuiting works, I'd recommending checking other answers.这个答案非常详细地介绍了 JavaScript 中如何工作,以及所有问题和相关主题,例如运算符优先级,如果您正在寻找快速定义并且已经了解短路的工作原理,我会推荐检查其他答案。


What we (thought we) knew so far:到目前为止我们(认为我们)知道的:

First let's inspect the behaviour we are all familiar with, inside the if() block, where we use && to check whether the two things are true :首先让我们检查一下我们都熟悉的行为,在if()块中,我们使用&&来检查这两件事是否为true

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

Now, your first instinct is probably to say: 'Ah yes, quite simple, the code executes the statement if both expr1 and expr2 are evaluated as true '现在,您的第一直觉可能会说: “啊,是的,很简单,如果expr1expr2都被评估为true ,代码就会执行语句”

Well, yes and no.嗯,是和不是。 You are technically correct, that is the behaviour you described, but that's not exactly how the code is evaluated and we'll need to delve deeper in order to fully understand.您在技术上是正确的,这就是您所描述的行为,但这并不是评估代码的方式,我们需要深入研究才能完全理解。


How exactly is the && and || &&||究竟是怎样的interpreted?:解释?:

It's time to look "under the hood of the engine".是时候看看“ 引擎的”了。 Let's consider this practical example:让我们考虑这个实际例子:

 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);

Well the result is 260 .. but why?结果是260 .. 但为什么呢? In order to get the answer, we need to understand how does the short-circuit evaluation work.为了得到答案,我们需要了解短路评估是如何工作的。

By the MDN Definition the && operator in expr1 && expr2 is executed followingly:MDN定义&&运营商在expr1 && expr2是从动地执行:

If expr1 can be converted to true , returns expr2 ;如果expr1可以转换为true ,则返回expr2 else, returns expr1 .否则,返回expr1

So this means, in our practical example, the const res is evaluated the following way:所以这意味着,在我们的实际示例中, const res的评估方式如下:

  1. Invoking expr1 - sanitise(0xFF)调用expr1 - sanitise(0xFF)
  2. 0xFF is a valid hexadecimal number for 250, otherwise I'd return NaN 0xFF是 250 的有效十六进制数,否则我将返回NaN
  3. The expr1 returned a "truthy" value, time to execute expr2 (otherwise I'd stop as NaN is falsy) expr1返回一个“真实”值,是执行expr2时间(否则我会停止,因为NaN是假的)
  4. Since userinput is truthy (a number), I can add +5 to it由于userinput是truthy(数字),我可以添加+5
  • "Truthy" means that expression can be evaluated as true. “Truthy”意味着表达式可以被评估为真。 Here's a list of truthy and falsy expressions.这是一个truthyfalsy表达式的列表。

So here, we were able to avoid additional if blocks and further isNaN checks with a simple usage of the && operator.所以在这里,我们能够避免额外的if块,并使用&&运算符的简单用法进一步检查isNaN


How it really works:它是如何工作的:

By now, we should at least have a picture how the operators work.到现在为止,我们至少应该了解运算符的工作原理。 The universal rule goes:通用规则是:

  • (some falsy expression) && expr will evaluate to falsy expression (some falsy expression) && expr将计算为假表达式
  • (some truthy expression) || expr (some truthy expression) || expr will evaluate to truthy expression (some truthy expression) || expr将评估为真表达式

Here are some further examples for better comprehension:以下是一些进一步的示例,以便更好地理解:

 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');` */


One last pesky, but very important thing [Operator Precedence]:最后一件讨厌但非常重要的事情[运算符优先级]:

Nice, hopefully you're getting the hang of it!很好,希望你能掌握它! Last thing we need to know is a rule about operator precedence, that is:我们需要知道的最后一件事是关于运算符优先级的规则,即:

  • The && operator is always executed prior to the || &&运算符总是在||之前执行operator.操作员。

Consider the following example:考虑以下示例:

 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

This will return as, perhaps confusingly to some as a() .这将作为a()返回,可能会令人困惑。 Reason is quite simple, it's just our eye-sight that's kind of deceiving us, because we're used to reading left-to-right.原因很简单,只是我们的视力在欺骗我们,因为我们习惯于从左到右阅读。 Let's take the console.log() and what not out and focus purely on the evaluation让我们把console.log()和什么不出来,完全专注于评估

true || false && false

Now to wrap your head around this:现在让你的头脑围绕这个:

  1. We said the && operator has precedence, so it gets evaluated as first.我们说&&运算符具有优先级,因此它被评估为第一个。 To help us better imagine the evaluation, think of the definition为了帮助我们更好地想象评估,想想定义

    expr1 && expr2

    Where:在哪里:

    • expr2 is false expr2false
    • expr1 is true || false expr1true || false true || false
  2. So that was the tricky part, now true || false所以这是棘手的部分,现在是true || false true || false is evaluated (the expr1 - left-side of the && ). true || false被评估( expr1 - &&左侧)。

    • Given the ||鉴于|| operator stops execution if expr1 || expr2运算符在expr1 || expr2停止执行expr1 || expr2 in expr1 evaluates as truthy, the expr1 is executed and code execution stops. expr1 || expr2expr1计算结果为truthy,所述expr1被执行,代码执行停止。
  3. The returned value is true返回值为true

Well.. that was pretty tricky, all because of few weird rules and semantics.嗯..这很棘手,因为很少有奇怪的规则和语义。 But remember, you can always escape operator precedence with the () - just like in math但请记住,您始终可以使用()来逃避运算符优先级 -就像在数学中一样

 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() */

The idea is that logical expressions are read left-to-right, and if the value of the left condition is enough to get the total value, the right condition will not be processed and evaluated.这个想法是从左到右读取逻辑表达式,如果左条件的值足以得到总值,则不会处理和评估右条件。 Some very simple examples:一些非常简单的例子:

 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>

The first two cases above will print to console results true and false respectively and you will not even see the modal window asking you to press "OK" or "Cancel", because the left condition is sufficient to define the total result.上面的前两种情况将分别打印到控制台结果truefalse ,您甚至不会看到要求您按“确定”或“取消”的模式窗口,因为左侧条件足以定义总结果。 On the contrary, with the cases 3–6, you will see the modal window asking for your choice, because the former two depend on the right part (that is your choice), and the latter two — regardless of the fact that the aggregate values of these expressions do not depend on your choice — because left conditions are read first.相反,在情况 3-6 中,您将看到模态窗口要求您选择,因为前两者取决于正确的部分(即您的选择),而后两者 - 无论聚合这些表达式的值不取决于您的选择——因为首先读取左条件。 So, it is important to place conditions left-to-right based on which ones you want to be processed first.因此,根据要首先处理的条件从左到右放置条件非常重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM