优先级和结合性
考虑由下面的表示法描述的表达式。其中,OP1 和 OP2 都是操作符的占位符。
a OP1 b OP2 c
左结合(左到右)相当于把左边的子表达式加上小括号 (a OP b) OP c,右结合(右到左)相当于 a OP (b OP c)。
赋值运算符是右结合的,所以你可以这么写:
a = b = 5; // 相当于 a = (b = 5);
预期结果是 a 和 b 的值都会成为 5。这是因为赋值运算符的返回结果就是赋值运算符右边的那个值,具体过程是:首先 b 被赋值为 5,然后 a 也被赋值为 b = 5 的返回值,也就是 5。
另一个例子是,只有幂运算符是右结合的,而其他算术运算符都是左结合的。有趣的是,无论结合性和优先级如何,求值顺序总是从左到右。
幂运算符 **
function echo(name, num) {
console.log("Evaluating the " + name + " side");
return num;
}
// 注意这里左边和中间的被圆括号包围的求幂表达式
console.log((echo("left", 2) ** echo("middle", 3)) ** echo("right", 2));
上述求值顺序是从左到右的:
Evaluating the left side
Evaluating the middle side
Evaluating the right side
64
幂运算符是右结合的,所以 2 ** 3 ** 2 与 2 ** (3 ** 2) 是相同的。因此,(2 ** 3) ** 2 会更改执行顺序,并导致输出上表中的 64。
分组和短路的注意事项
在下表中,分组(Grouping) 具有最高优先级。然而,这并不意味着总是优先对分组符号 ( … ) 内的表达式进行求值,尤其是涉及短路时。
短路是条件求值的术语。例如,在表达式 a && (b + c) 中,如果 a 为虚值(falsy),那么即使 (b + c) 在圆括号中,也不会被求值。我们可以说逻辑或运算符(“OR”)是“短路的”。除了逻辑或运算符外,其他短路运算符还包括逻辑与(“AND”)、空值合并、可选链和条件(三元)运算符。下面有更多例子:
a || (b * c); // 首先对 `a` 求值,如果 `a` 为真值则直接返回 `a`
a && (b < c); // 首先对 `a` 求值,如果 `a` 为虚值则直接返回 `a`
a ?? (b || c); // 首先对 `a` 求值,如果 `a` 不是 `null` 或 `undefined` 则直接返回 `a`
a?.b.c; // 首先对 `a` 求值,如果 `a` 是 `null` 或 `undefined` 则直接返回 `undefined`
示例
3 > 2 && 2 > 1
// 返回 true
3 > 2 > 1
// 返回 false,因为 3 > 2 是 true,然后 true 会在比较运算符中
// 被隐式转换为 1,因此 true > 1 会变为 1 > 1,结果是 false
// 加括号可以更清楚:(3 > 2) > 1
true 会在比较运算符中被隐式转换为 1
使用建议
() 为所有运算符中最高优先级,在你不明确运算符的优先级时,可以用 () 显式的标明优先级。
参考
具体优先级可看参考汇总表