繁体   English   中英

JavaScript 有“短路”评估吗?

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

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

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

现场演示

这个答案非常详细地介绍了 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定义&&运营商在expr1 && expr2是从动地执行:

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

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

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

所以在这里,我们能够避免额外的if块,并使用&&运算符的简单用法进一步检查isNaN


它是如何工作的:

到现在为止,我们至少应该了解运算符的工作原理。 通用规则是:

  • (some falsy expression) && expr将计算为假表达式
  • (some truthy 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 true || false
  2. 所以这是棘手的部分,现在是true || false true || false被评估( expr1 - &&左侧)。

    • 鉴于|| 运算符在expr1 || expr2停止执行 expr1 || expr2expr1计算结果为truthy,所述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() */

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

 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>

上面的前两种情况将分别打印到控制台结果truefalse ,您甚至不会看到要求您按“确定”或“取消”的模式窗口,因为左侧条件足以定义总结果。 相反,在情况 3-6 中,您将看到模态窗口要求您选择,因为前两者取决于正确的部分(即您的选择),而后两者 - 无论聚合这些表达式的值不取决于您的选择——因为首先读取左条件。 因此,根据要首先处理的条件从左到右放置条件非常重要。

暂无
暂无

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

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