我想知道 JavaScript 是否有像 C# 中的 && 运算符这样的“短路”评估。如果没有,我想知道是否有可行的解决方法。
JavaScript 有“短路”评估吗?
这个答案非常详细地介绍了如何 短路在 JavaScript 中工作,具有所有问题以及相关主题,例如运算符优先级,如果您正在寻找快速定义并且已经了解短路的工作原理,我建议您查看其他答案。
到目前为止我们(认为我们)知道的:
首先让我们检查一下我们都熟悉的行为,在if()
块内部,我们&&
用来检查两件事是否是true
:
if (true && true) {
console.log('bar');
}
现在,你的第一react可能是说:“是啊,很简单,代码执行,如果双方的陈述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
返回“truthy”值,执行时间expr2
(否则我会停止为NaN
是falsy) - 由于
userinput
是真的(一个数字),我可以添加+5
它
因此,在这里,我们能够通过简单地使用运算符来避免额外的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
这将返回 as,对于某些 as 可能会造成混淆a()
。原因很简单,只是我们的视力在欺骗我们,因为我们习惯于从左到右阅读。让我们把console.log()
和不出去的东西完全放在评估上
true || false && false
现在让你的头脑围绕这个:
我们说
&&
操作符有优先权,所以它被评估为第一个。为了帮助我们更好地想象评估,想想定义expr1 && expr2
在哪里:
expr2
是false
expr1
是true || false
所以这是棘手的部分,现在
true || false
进行评估(expr1
- 的左侧&&
)。||
如果expr1 || expr2
inexpr1
评估为真,则运算符停止执行,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 中,您将看到模态窗口要求您进行选择,因为前两者取决于正确的部分(即您的选择),而后两者 - 无论聚合这些表达式的值不取决于您的选择——因为首先读取左条件。因此,根据要首先处理的条件从左到右放置条件非常重要。