[英]Does JavaScript have “Short-circuit” evaluation?
我想知道 JavaScript 是否有像 C# 中的 && 运算符这样的“短路”评估。 如果没有,我想知道是否有一种可行的解决方法可以采用。
这个答案非常详细地介绍了 JavaScript 中的短路如何工作,以及所有问题和相关主题,例如运算符优先级,如果您正在寻找快速定义并且已经了解短路的工作原理,我会推荐检查其他答案。
首先让我们检查一下我们都熟悉的行为,在if()
块中,我们使用&&
来检查这两件事是否为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 的有效十六进制数,否则我将返回NaN
expr1
返回一个“真实”值,是执行expr2
时间(否则我会停止,因为NaN
是假的)userinput
是truthy(数字),我可以添加+5
吧 所以在这里,我们能够避免额外的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
现在让你的头脑围绕这个:
我们说&&
运算符具有优先级,因此它被评估为第一个。 为了帮助我们更好地想象评估,想想定义
expr1 && expr2
在哪里:
expr2
是false
expr1
为true || false
true || false
所以这是棘手的部分,现在是true || false
true || false
被评估( expr1
- &&
左侧)。
||
运算符在expr1 || expr2
停止执行 expr1 || expr2
在expr1
计算结果为truthy,所述expr1
被执行,代码执行停止。 返回值为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>
上面的前两种情况将分别打印到控制台结果true
和false
,您甚至不会看到要求您按“确定”或“取消”的模式窗口,因为左侧条件足以定义总结果。 相反,在情况 3-6 中,您将看到模态窗口要求您选择,因为前两者取决于正确的部分(即您的选择),而后两者 - 无论聚合这些表达式的值不取决于您的选择——因为首先读取左条件。 因此,根据要首先处理的条件从左到右放置条件非常重要。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.