JavaScript有“短路”评估吗?

2022-08-30 04:22:03

我想知道JavaScript是否有像C#中的&&Operator那样的“短路”评估。如果没有,我想知道是否有一种可行的解决方法可以采用。


答案 1

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

现场演示


答案 2

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


到目前为止,我们(认为我们)所知道的:

首先,让我们检查一下我们都熟悉的行为,在块内,我们用来检查这两件事是否是:if()&&true

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

现在,你的第一个直觉可能是说:“啊,是的,很简单,如果expr1expr2都被评估为,代码就会执行语句。

好吧,是和不是。从技术上讲,你是对的,这就是你描述的行为,但这并不是评估代码的确切方式,我们需要深入研究才能完全理解。


和 究竟是如何解释的?&&||

现在是时候看看“在引擎的引擎盖下”。让我们考虑一下这个实际的例子:

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

如果可以转换为 ,则返回 ;否则,返回 。expr1trueexpr2expr1

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

  1. 调用expr1 - sanitise(0xFF)
  2. 0xFF是 250 的有效十六进制数,否则我会返回NaN
  3. 返回一个“真实”值,执行时间(否则我会停止,因为NaN是假的)expr1expr2
  4. 既然是真(一个数字),我可以加进去userinput+5
  • “真实”意味着表达式可以评估为真实。以下是真实虚假表达的列表。

因此,在这里,我们能够通过运算符的简单使用来避免额外的块和进一步的检查。ifisNaN&&


它是如何工作的:

到现在为止,我们至少应该了解算子是如何工作的。普遍规则是:

  • (一些虚假的表达)&&expr将评估为虚假的表达
  • (一些真话表达式)|| 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 || 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()  
*/