JavaScript - 运算符优先级
在 JavaScript 中,operator precedence(运算符优先级)确保了当单个表达式包含多个运算符时,这些运算符的执行优先顺序。因此,具有更高优先级的表达式会被编译器首先执行,然后再执行优先级较低的运算符。
当你编写只包含 1 个或 2 个运算符的 JavaScript 表达式时,你可以轻松理解表达式的输出结果。但当表达式包含多个运算符时,你需要了解 operator precedence(运算符优先级)的概念,才能正确求值表达式。
operator precedence(运算符优先级)的最佳示例是,在传统数学中,乘法运算符的优先级高于加法或减法运算符。因此,如果数学表达式同时包含乘法和加法运算符,你需要先执行乘法运算。
结合性
结合性(associativity)指的是编译器在求值表达式时应该遵循的方向。在许多情况下,运算符具有相同的优先级。这种情况下,会出现歧义,即编译器应该先执行哪个操作。因此,编译器会借助结合性规则。它可以是从左到右或从右到左。
例如,我们需要执行以下表达式。
let res = 50/5*2;
将上述表达式视为 (50/5) * 2,结果为 20。
将表达式视为 50/ (5*2),结果为 5。
为了解决上述歧义,编译器使用结合性规则。除法和乘法运算符的结合性是从左到右。因此,它将表达式求值为 (50 / 5) * 2。
赋值运算符具有从右到左的结合性。考虑以下赋值表达式。
P = q = 90;
在上述表达式中,90 被赋值给 q,然后 q 的值被赋值给 p。
简而言之,JavaScript 编译器根据 operator precedence(运算符优先级)求值表达式,当多个运算符具有相同优先级时,它使用结合性规则。
运算符优先级表
下面的表格包含运算符、其描述、结合方向以及简短示例。
| 优先级 | 运算符 | 描述 | 结合性 | 示例 |
|---|---|---|---|---|
| 1 | () | 分组 | L -> R | (expression) |
| 2 | . | 对象成员 | L -> R | Object_name.property |
| 2 | () | 函数调用 | L -> R | Demo() |
| 2 | new | 创建对象 | R -> L | New test() |
| 2 | [] | 对象成员 | L -> R | Object["property"] |
| 3 | -- | 后缀递减 | - | p--; |
| 3 | ++ | 后缀递增 | - | p++ |
| 4 | -- | 前缀递减 | R -> L | --p; |
| 4 | ++ | 前缀递增 | R -> L | ++p; |
| 4 | typeof | 获取变量类型 | R -> L | typeof a; |
| 4 | ! | 逻辑非 | R -> L | !a; |
| 4 | ~ | 按位非 | R -> L | ~p |
| 4 | - | 一元减法 | R -> L | -p |
| 4 | + | 一元加法 | R -> L | +p |
| 4 | delete | 删除对象属性 | R -> L | Delete arr[0] |
| 4 | void | 计算 void | R -> L | Void(1) |
| 5 | ** | 幂运算符 | R -> L | p ** q |
| 6 | * | 乘法 | L -> R | p * q |
| 6 | / | 除法 | L -> R | p / q |
| 6 | % | 模运算 | L -> R | p % q |
| 7 | + | 加法或正号运算符 | L -> R | p + q |
| 7 | - | 减法运算符 | L -> R | p - q |
| 8 | << | 左移 | L -> R | p << 2 |
| 8 | >> | 有符号右移 | L -> R | p >> 2 |
| 8 | >>> | 无符号右移 | L -> R | p >>> 2 |
| 9 | in | 属性在对象中 | L -> R | x in y |
| 9 | instanceof | 对象实例 | L -> R | p instanceof Object |
| 9 | < | 小于 | L -> R | p < q |
| 9 | <= | 小于或等于 | L -> R | p <= q |
| 9 | > | 大于 | L -> R | p > q |
| 9 | >= | 大于或等于 | L -> R | p >= q |
| 10 | == | 相等 | L -> R | p == q |
| 10 | != | 不相等 | L -> R | p != q |
| 10 | === | 严格相等 | L -> R | p === q |
| 10 | !== | 严格不相等 | L -> R | p !== q |
| 11 | & | 按位与 | L -> R | p & q |
| 12 | ^ | 按位异或 | L -> R | p ^ q |
| 13 | | | 按位或 | L -> R | p | q |
| 14 | && | 逻辑与 | L -> R | p && q |
| 15 | || | 逻辑或 | L -> R | p || q |
| 16 | ?? | 空值合并 | R -> L | p ?? q |
| 17 | = | 赋值 | R -> L | p = q |
| 17 | : | 冒号赋值 | R -> L | p : q |
| 17 | += | 加法赋值 | R -> L | p += q |
| 17 | -= | 减法赋值 | R -> L | p -= q |
| 17 | *= | 乘法赋值 | R -> L | p *= q |
| 17 | /= | 除法赋值 | R -> L | p /= q |
| 17 | %= | 模运算赋值 | R -> L | p %= q |
| 17 | **= | 幂运算赋值 | R -> L | p **= q |
| 17 | <<= | 左移赋值 | R -> L | p <<= q |
| 17 | >>= | 右移赋值 | R -> L | p >>= q |
| 17 | >>>= | 无符号右移赋值 | R -> L | p >>>= q |
| 17 | &= | 按位与赋值 | R -> L | p &= q |
| 17 | ^= | 按位异或赋值 | R -> L | p ^= q |
| 17 | |= | 按位或赋值 | R -> L | p |= q |
| 17 | &&= | 逻辑与赋值 | R -> L | p &&= q |
| 17 | ||= | 逻辑或赋值 | R -> L | p ||= q |
| 17 | => | 箭头运算符 | - | (a, b )=> { // function code} |
| 17 | 展开运算符 | - | [ arr] | |
| 18 | yield | 暂停/恢复 | R -> L | yield p; |
| 19 | , | 逗号运算符 | L -> R | (10, 20, 30) |
示例
让我们通过简单的示例来理解运算符优先级。
示例
在下面的示例中,第一个表达式包含具有相同优先级的除法、取模和乘法运算符。因此,编译器将使用结合性规则,对于乘法、除法和取模运算符是从左到右结合。
因此,它先将 30 除以 15,然后计算 (30/15) 对 3 的取模,最后将 ((30/15)%3) 与 2 相乘。
在第二个表达式中,幂运算符具有从右到左的结合性。因此,它以与 (2 * 8 ** (3 ** 2)) 相同的方式求值表达式。
<html>
<body>
<div id = "output"></div>
<script>
const first = 30 / 15 % 3 * 2;
const second = 2 ** 3 ** 2;
document.getElementById("output").innerHTML =
"The value of first expression is : " + first + "<br>" +
"The value of second expression is : " + second;
</script>
</body>
</html>
输出
它将产生以下结果 −
The value of first expression is : 4 The value of second expression is : 512
示例
这段代码演示了如何使用分组运算符 () 来改变运算符优先级。在下面的代码中,我们使用了与上面代码相同的表达式,但改变了运算符优先级。
在第一个表达式中,首先计算取模并将结果值与 2 相乘。因此,我们得到 0,然后 30 除以 0,返回 Infinity。
在第二个表达式中,首先计算 (2 ** 3) 和 (8 ** 2),结果等于 64。
<html>
<body>
<div id = "output"></div>
<script>
const first = 30 / ((15 % 3) * 2);
const second = (2 ** 3) ** 2;
document.getElementById("output").innerHTML =
"The value of first expression is : " + first + "<br>" +
"The value of second expression is : " + second;
</script>
</body>
</html>
输出
The value of first expression is : Infinity The value of second expression is : 64
分组运算符可以改变任何运算符的优先级,因为它具有最高的运算符优先级。