我想知道JavaScript是否有"短路"评估像&& C#中的运算符。如果没有,我想知道是否有采用合理的解决方法。
答案 0 :(得分:102)
是的,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.
}
答案 1 :(得分:3)
这个答案非常详细地介绍了short-circuiting在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 Definition
&&
中的expr1 && expr2
运算符执行如下:如果
expr1
可以转换为true
,则返回expr2
;否则,返回expr1
。
因此,在我们的实际示例中,这意味着const res
的评估方式如下:
expr1
-sanitise(0xFF)
0xFF
是250的有效十六进制数,否则我将返回NaN
expr1
返回了一个“真实的”值,该执行expr2
的时间了(否则我会因为NaN
虚假而停下来) userinput
是真实的(数字),因此我可以在其中添加+5
因此,在这里,我们可以通过简单地使用if
运算符来避免额外的isNaN
块,并进一步避免&&
的检查。
现在,我们至少应该了解short-circuit运算符的工作方式。通用规则是:
(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
现在将您的头围起来:
我们说过&&
运算符具有优先权,因此它被优先评估。为了帮助我们更好地想象评估,请考虑一下定义
expr1 && expr2
位置:
expr2
是false
expr1
是true || false
这是棘手的部分,现在评估true || false
(expr1
-&&
的左侧)。
||
中的expr1 || expr2
被评估为真,expr1
运算符就停止执行,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()
*/
答案 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 ,您甚至都不会看到模态窗口要求您按“确定”或“取消” ”,因为左侧条件足以定义总结果。
相反,在接下来的四个表达式中,您将看到模态窗口询问您的选择,因为前两个依赖于正确的部分(即您的选择),后两个依赖于正确的部分结果不取决于您的选择-因为首先读取左侧条件。因此,重要的是根据要首先处理的条件从左到右放置条件。