为什么当运算符优先级表明短路评估不应该时短路评估会起作用?

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

... 其中 ABC 可以只是变量,也可以是其他表达式,例如方法调用。在Java中,这保证被评估为:

  • 评估A(并记住以备后用)
  • 评价B
  • 评价C
  • BC
  • 的计算结果相乘
  • A 的计算结果与乘法
  • 的结果相加

请注意,尽管 * 的优先级高于 +,但 A 仍然在 BC 之前计算。如果您想要考虑顺序方面的优先级,请注意乘法如何仍然发生在加法之前 - 但它仍然满足从左到右的计算顺序。

根据语言规范,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,则第二个参数甚至不会被计算。