JavaScript有“短路”评估吗?

时间:2012-09-23 17:34:17

标签: javascript short-circuiting

我想知道JavaScript是否有"短路"评估像&& C#中的运算符。如果没有,我想知道是否有采用合理的解决方法。

3 个答案:

答案 0 :(得分:102)

是的,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

答案 1 :(得分:3)

这个答案非常详细地介绍了在JavaScript中的工作方式,包括所有陷阱以及相关主题,例如运算符优先级,,如果您正在寻找一个快速定义并且已经了解了它的简短程度,电路工作,我建议检查其他答案。


到目前为止,我们(我们认为)知道什么:

首先让我们在if()块中检查我们都熟悉的行为,在其中使用&&来检查两件事是否为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 Definition   &&中的expr1 && expr2运算符执行如下:

     

如果expr1可以转换为true,则返回expr2;否则,返回expr1

因此,在我们的实际示例中,这意味着const res的评估方式如下:

  1. 调用expr1-sanitise(0xFF)
  2. 0xFF是250的有效十六进制数,否则我将返回NaN
  3. expr1返回了一个“真实的”值,该执行expr2的时间了(否则我会因为NaN虚假而停下来)
  4. 由于userinput是真实的(数字),因此我可以在其中添加+5
  
      
  • “ Truthy”表示可以将表达式评估为true。这是一个清单   truthy和   falsy   表达式。
  •   

因此,在这里,我们可以通过简单地使用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');`
*/


最后一个令人讨厌的事情,但非常重要的事情[操作员优先]:

很好,希望您能掌握它!我们需要知道的最后一件事是关于运算符优先级的规则,即:

  • &&运算符总是在||运算符之前执行。

考虑以下示例:

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 || falseexpr1-&&的左侧)。

    • 如果||中的expr1 || expr2被评估为真,expr1运算符就停止执行,expr1被执行并且代码执行停止。
  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()  
*/

答案 2 :(得分:1)

这个想法是从左到右读取逻辑表达式,如果左条件的值足以获取总值,则不会处理和评估右条件。一些非常简单的示例:

console.log (1 === 1 || confirm("Press OK or Cancel"));
console.log (1 === 2 && confirm("Press OK or Cancel"));

console.log (1 === 2 || confirm("Press OK or Cancel"));
console.log (1 === 1 && confirm("Press OK or Cancel"));
console.log (confirm("Press OK or Cancel") || 1 === 1);
console.log (confirm("Press OK or Cancel") && 1 === 2);

上面的前两个表达式将分别打印到控制台结果 true false ,您甚至都不会看到模态窗口要求您按“确定”或“取消” ”,因为左侧条件足以定义总结果。

相反,在接下来的四个表达式中,您将看到模态窗口询问您的选择,因为前两个依赖于正确的部分(即您的选择),后两个依赖于正确的部分结果不取决于您的选择-因为首先读取左侧条件。因此,重要的是根据要首先处理的条件从左到右放置条件。