为什么当运算符优先级表明短路评估不应该时短路评估会起作用?
Why does short-circuit evaluation work when operator precedence says it shouldn't?
In JavaScript and Java, the equals operator (==
or ===
) has a higher precedence than the OR operator (||
). Yet both languages (JS, Java) 支持 if
语句中的短路:
当我们有 if(true || anything())
时,anything()
不被计算。
您还可以使用以下表达式:true || foo == getValue())
- 例如在输出语句中 console.log(...);
,或在赋值中。
现在,根据运算符的优先级,短路应该不会发生,因为 ===
= ==
> ||
在优先级方面。 (换句话说,应该首先进行比较,因此应该调用 getValue()
,因为相等性检查的优先级高于 OR 比较。)但确实如此。 getValue()
未被调用(可以通过将输出语句放入其主体中轻松检查)。
为什么(当运算符优先级表示不应该短路时短路会起作用)?
还是我把事情搞糊涂了?
Or am I confusing matters?
你是。我认为将优先级视为 grouping 比排序要简单得多。它会影响评估顺序,但只是 因为 它会更改分组。
我不确定 Java 脚本,但在 Java 中,操作数总是按从左到右的顺序求值。 ==
的优先级高于 ||
的事实仅意味着
true || foo == getValue()
被评估为
true || (foo == getValue())
而不是
(true || foo) == getValue()
如果您只是以这种方式考虑优先级,然后考虑求值总是从左到右(因此 ||
的左操作数总是在右操作数之前求值,例如)然后一切都很简单 - getValue()
永远不会因短路而被评估。
要从等式中消除短路,请考虑以下示例:
A + B * C
... 其中 A
、B
和 C
可以只是变量,也可以是其他表达式,例如方法调用。在Java中,这保证被评估为:
- 评估
A
(并记住以备后用)
- 评价
B
- 评价
C
- 将
B
和 C
的计算结果相乘
- 将
A
的计算结果与乘法 的结果相加
请注意,尽管 *
的优先级高于 +
,但 A
仍然在 B
或 C
之前计算。如果您想要考虑顺序方面的优先级,请注意乘法如何仍然发生在加法之前 - 但它仍然满足从左到右的计算顺序。
根据语言规范,https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24
At run time, the left-hand operand expression is evaluated first; if the result has type Boolean, it is subjected to unboxing conversion (§5.1.8).
If the resulting value is true, the value of the conditional-or expression is true and the right-hand operand expression is not evaluated.
因此,如果您有 a || b==c
,它不会被解释为 (a || b) == c
,因为 ||
的优先级较低,正如您在教程中所见。相反,它被解释为 a || (b==c)
。现在因为 a
是 ||
的左边,它首先被评估。
在这种情况下没有运算符优先级。您所质疑的就像在 f(callback)
语句中 callback
函数甚至在 f
之前被评估。这不可能发生。
另一方面,在 JS 中,||
是为数不多的几个可以观看懒惰表演的地方之一。 ==
操作数(把它想象成全功能语言中的一个中缀函数)有两个参数,左边的第一个被计算。如果它解析为 true
,则第二个参数甚至不会被计算。
In JavaScript and Java, the equals operator (==
or ===
) has a higher precedence than the OR operator (||
). Yet both languages (JS, Java) 支持 if
语句中的短路:
当我们有 if(true || anything())
时,anything()
不被计算。
您还可以使用以下表达式:true || foo == getValue())
- 例如在输出语句中 console.log(...);
,或在赋值中。
现在,根据运算符的优先级,短路应该不会发生,因为 ===
= ==
> ||
在优先级方面。 (换句话说,应该首先进行比较,因此应该调用 getValue()
,因为相等性检查的优先级高于 OR 比较。)但确实如此。 getValue()
未被调用(可以通过将输出语句放入其主体中轻松检查)。
为什么(当运算符优先级表示不应该短路时短路会起作用)?
还是我把事情搞糊涂了?
Or am I confusing matters?
你是。我认为将优先级视为 grouping 比排序要简单得多。它会影响评估顺序,但只是 因为 它会更改分组。
我不确定 Java 脚本,但在 Java 中,操作数总是按从左到右的顺序求值。 ==
的优先级高于 ||
的事实仅意味着
true || foo == getValue()
被评估为
true || (foo == getValue())
而不是
(true || foo) == getValue()
如果您只是以这种方式考虑优先级,然后考虑求值总是从左到右(因此 ||
的左操作数总是在右操作数之前求值,例如)然后一切都很简单 - getValue()
永远不会因短路而被评估。
要从等式中消除短路,请考虑以下示例:
A + B * C
... 其中 A
、B
和 C
可以只是变量,也可以是其他表达式,例如方法调用。在Java中,这保证被评估为:
- 评估
A
(并记住以备后用) - 评价
B
- 评价
C
- 将
B
和C
的计算结果相乘
- 将
A
的计算结果与乘法 的结果相加
请注意,尽管 *
的优先级高于 +
,但 A
仍然在 B
或 C
之前计算。如果您想要考虑顺序方面的优先级,请注意乘法如何仍然发生在加法之前 - 但它仍然满足从左到右的计算顺序。
根据语言规范,https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.24
At run time, the left-hand operand expression is evaluated first; if the result has type Boolean, it is subjected to unboxing conversion (§5.1.8).
If the resulting value is true, the value of the conditional-or expression is true and the right-hand operand expression is not evaluated.
因此,如果您有 a || b==c
,它不会被解释为 (a || b) == c
,因为 ||
的优先级较低,正如您在教程中所见。相反,它被解释为 a || (b==c)
。现在因为 a
是 ||
的左边,它首先被评估。
在这种情况下没有运算符优先级。您所质疑的就像在 f(callback)
语句中 callback
函数甚至在 f
之前被评估。这不可能发生。
另一方面,在 JS 中,||
是为数不多的几个可以观看懒惰表演的地方之一。 ==
操作数(把它想象成全功能语言中的一个中缀函数)有两个参数,左边的第一个被计算。如果它解析为 true
,则第二个参数甚至不会被计算。