运算符优先级

运算符优先级确定如何分析运算符之间的相互关系。优先级较高的运算符成为优先级较低的运算符的操作数。

试试看

优先级和关联性

考虑一个可由下面的表示描述的表达式,其中操作1OP2(操作2)是用于OPerator的填充板。

a OP1 b OP2 c

上述组合有两种可能的解释:

(a OP1 b)OP2 ca OP1(b OP2 c)

语言决定采用哪一种取决于操作1OP2(操作2).

如果操作1OP2(操作2)具有不同的优先级(见下表),运算符的优先级较高优先首先,关联性并不重要。观察乘法如何比加法具有更高的优先级,并首先执行,即使加法是在代码中首先写入的。

js公司
控制台.log(3+10*2);//23控制台.log(3+(10*2));//23,因为这里的括号是多余的控制台.log((3+10)*2);//26,因为括号改变了顺序

在具有相同优先级的运算符中,语言按以下方式对其进行分组结合性.左旋社交(从左到右)表示它被解释为(a OP1 b)OP2 c,同时权利社会性(从右到左)表示它被解释为a OP1(b OP2 c)。赋值运算符是右关联的,因此您可以编写:

js公司
a=b=5;//与书写a=(b=5)相同;

预期结果是b得到值5。这是因为赋值运算符返回所赋值。第一,b设置为5。然后也设置为5-的返回值b=5,也称为赋值的右操作数。

另一个例子是,唯一指数运算符具有右关联性,而其他算术运算符具有左关联性。

js公司
常数a=4**3**2;//同4**(3**2);评估为262144常数b=4/3/2;//与(4/3)/2相同;评估值为0.6666。。。

操作符首先按优先级分组,然后,对于具有相同优先级的相邻操作符,则按关联性分组。所以,当混合除法和求幂时,求幂总是在除法之前。例如,2 ** 3 / 3 ** 2结果为0.88888888888,因为它与(2 ** 3) / (3 ** 2).

对于前缀一元运算符,假设我们有以下模式:

OP1和OP2 b

哪里操作1是前缀一元运算符,并且OP2(操作2)是二进制运算符。如果操作1优先级高于OP2(操作2),则将其分组为(OP1 a)OP2 b; 否则,就会OP1(一个OP2 b).

js公司
常数a=1;常数b=2;a+b类型;//相当于(a型)+b;结果是“数字2”

如果一元运算符位于第二个操作数上:

a OP2 OP1 b

然后是二进制运算符OP2(操作2)必须具有低于一元运算符的优先级操作1将其分组为a OP2(OP1b)。例如,以下内容无效:

js公司
函数*foo(){a+产量1;}

因为+优先级高于产量,这将成为(a+产量)1-但是因为产量是一个保留字在生成器函数中,这将是一个语法错误。幸运的是,大多数一元运算符的优先级都高于二进制运算符,因此不会受到此缺陷的影响。

如果我们有两个前缀一元运算符:

OP1 OP2一个

然后一元运算符更接近操作数,OP2(操作2)的优先级必须高于操作1将其分组为OP1(OP2 a)。有可能以另一种方式得到它,最终(OP1 OP2)a:

js公司
异步函数*foo(){等待产量1;}

因为等待优先级高于产量,这将成为(等待产量)1,它正在等待名为产量和语法错误。同样,如果你有新的!A;,因为!优先级低于新的,这将成为(新!)A,这显然是无效的。(无论如何,写这段代码看起来毫无意义,因为!A类总是生成布尔值,而不是构造函数。)

对于后缀一元运算符(即,++--),同样的规则也适用。幸运的是,这两个操作符的优先级都高于任何二进制操作符,因此分组始终是您所期望的。此外,因为++计算为价值,不是参考,也不能像在C语言中那样将多个增量链接在一起。

js公司
设a=1;a++++;//语法错误:后缀操作中的左侧无效。

将处理操作员优先级递归地。例如,考虑以下表达式:

js公司
1 + 2 ** 3 * 4 / 5 >> 6

首先,我们通过降低优先级来对不同优先级的操作符进行分组。

  1. 这个**运算符具有最高优先级,因此它首先分组。
  2. 环顾四周**表情,它有*在右边和+在左边。*具有更高的优先级,因此首先对其进行分组。*/具有相同的优先级,所以我们暂时将它们分组。
  3. 环顾四周*//表达式分组为2,因为+优先级高于>>,前者被分组。
js公司
(1 + ( (2 ** 3) * 4 / 5) ) >> 6// │    │ └─ 1. ─┘        │ │// │    └────── 2───────┘ │// └────────── 三。──────────┘

*//组,因为它们都是左关联的,所以左操作数将被分组。

js公司
(1 + ( ( (2 ** 3) * 4 ) / 5) ) >> 6// │    │ │ └─ 1─┘     │    │ │// │    └─│─────── 2───│────┘ │// └──────│───── 三。─────│──────┘//        └───── 4. ─────┘

请注意,运算符优先级和关联性仅影响操作员(隐式分组),但不是操作数。操作数总是从左到右进行计算。通常首先计算高阶概率表达式,然后根据运算符优先级的顺序组合其结果。

js公司
函数echo(name,num){console.log(`评估${name}端`);返回num;}//指数运算符(**)是右关联的,//但是具有更高优先级的所有调用表达式(echo()),//将在**之前进行评估控制台.log(echo(“左”,4)**echo;//评估左侧//评估中间面//评估右侧// 262144//指数运算符(**)的优先级高于除法运算符(/),//但求值总是从左操作数开始控制台.log(echo(“左”,4)/echo(“中”,3)**echo,(“右”,2));//评估左侧//评估中间面//评估右侧// 0.4444444444444444

如果您熟悉二叉树,请将其视为后序遍历.

/┌────────┴────────┐echo(“左”,4)**┌────────┴────────┐echo(“中间”,3)echo

在所有操作符都正确分组后,二进制操作符将形成一个二叉树。评估从最外层的组开始,该组是优先级最低的运算符(/在这种情况下)。首先计算此运算符的左操作数,它可以由更高优先级的运算符(例如调用表达式)组成echo(“左”,4)). 左操作数求值后,右操作数以相同的方式求值。因此,所有叶节点-echo()调用-将从左到右访问,而不管加入它们的操作员的优先级如何。

短路

在上一节中,我们说过“总是先计算高阶precedence表达式”-这通常是正确的,但必须在确认短路,在这种情况下,可能根本不计算操作数。

短路是条件评估的行话。例如,在表达式中a&&(b+c),如果虚伪的,然后是子表达式(b+c)甚至不会被计算,即使它是分组的,因此其优先级高于&&。我们可以说逻辑AND运算符(&&)是“短路”。除了逻辑AND之外,其他短路运算符还包括逻辑OR(||),取消合并(??)和可选链接(?.).

js公司
a | |(b*c);//首先评估`a`,如果`a`是“真实的”,则生成`a`a&&(b<c);//首先计算`a`,如果`a`是“falsy”,则生成`a`a??(b||c);//首先计算`a`,如果`a`不为`null`且不为`undefined,则生成`a``a?。b.c;//首先计算`a`,如果`a`为`null`或`未定义`

计算短路运算符时,始终计算左操作数。只有当左操作数无法确定运算结果时,才会计算右操作数。

注:短路行为在这些操作符中得到了验证。其他运营商会总是计算这两个操作数,不管它是否真的有用-例如,NaN*foo()将始终呼叫foo公司即使结果是NaN公司.

先前的后序遍历模型仍然有效。然而,在访问了短路运算符的左子树之后,语言将决定是否需要计算右操作数。如果不是(例如,因为||已经是真的),直接返回结果,而无需访问正确的子树。

考虑这种情况:

js公司
函数A(){console.log('called A');返回false;}函数B(){console.log('called B');返回false;}函数C(){console.log('calledC');返回true;}console.log(C()||B()&&A());//日志://称为C//真的

仅限C()被评估,尽管&&具有更高的优先级。这并不意味着||在这种情况下具有更高的优先级因为 (B()&&A())具有更高的优先级,导致其整体被忽略。如果重新安排为:

js公司
console.log(A()&&C()||B());//日志://称为A//称为B//假

然后是短路效应&&只会阻止C()被评估,但因为A()和C()作为一个整体,B()仍将进行评估。

然而,请注意,短路不会改变最终评估结果。它只影响对操作数,而不是如何操作员分组-如果操作数的计算没有副作用(例如,记录到控制台、赋值给变量、抛出错误),则根本看不到短路。

这些运算符的赋值对应项(&&=,||=,??=)也是短路的。它们是短路的,任务根本不会发生。

下表按从最高优先级(18)到最低优先级(1)的顺序列出了运算符。

关于该表的几个一般注释:

  1. 这里包含的所有语法并不是严格意义上的“操作符”。例如,传播...和箭头=>通常不被视为操作员。然而,我们仍然包含了它们,以显示它们与其他操作符/表达式的绑定程度。
  2. 某些操作符具有某些操作数,这些操作数需要比高优先级操作符生成的表达式窄的表达式。例如,成员访问的右侧.(优先级17)必须是标识符,而不是分组表达式。箭头的左侧=>(优先级2)必须是参数列表或单个标识符,而不是某个随机表达式。
  3. 某些操作符具有某些操作数,这些操作数接受的表达式比由更高优先级操作符生成的表达式宽。例如,括号内括号表示法的封闭表达式[ … ](优先级17)可以是任何表达式,甚至可以是逗号(优先级1)连接的表达式。这些运算符的作用就像该操作数是“自动分组”的。在这种情况下,我们将省略关联性。
优先 关联性 单个操作员 笔记
18:分组 不适用 分组
(x)
[1]
17:接入和呼叫 从左到右 成员访问权限
x年
[2]
可选链接
x?。
不适用 计算成员访问
x[年]
[3]
新的带参数列表
新x(y)
[4]
函数调用
x(y)
导入(x)
16:新 不适用 新的没有参数列表
新x
15:后缀运算符 不适用 后缀增量
x个++
[5]
后缀减量
x个--
14:前缀运算符 不适用 前缀增量
++x个
[6]
前缀递减
--x个
逻辑NOT
!x个
按位取反
~x个
一元+
+x个
一元否定
-x个
x的类型
空隙x
删除x [7]
等待x
13:求幂 从右到左 指数化
x年*月
[8]
12:乘法运算符 从左到右 乘法
x年
部门
x年
剩余部分
x%年
11:加法运算符 从左到右 添加
x+y
减法
x-y
10:按位移位 从左到右 左移位
x<<y
右移
x>>y
无符号右移
x>>y
9:关系运算符 从左到右 小于
x<y
小于或等于
x≤y
大于
x>y
大于或等于
x>=y
x英寸y
y的x实例
8:等式运算符 从左到右 平等
x==y
不平等
x!=
严格平等
x===y
严格不等式
x!==
7:按位与 从左到右 按位与
x轴(&y)
6:按位异或 从左到右 按位异或
x ^y年
5:按位OR 从左到右 按位或
x | y(x | y)
4:逻辑与 从左到右 逻辑与
x和y
3:逻辑OR,零合并 从左到右 逻辑OR
x年
Nullish凝聚算子
x??个??
[9]
2:分配和杂项 从右到左 转让
x=y
[10]
加法赋值
x+=y
减法赋值
x-=y
指数赋值
x**=y
乘法赋值
x*=y
部门分配
x/=y
剩余分配
x%=y
左移位分配
x<<=y
右移分配
x>>=y
未签名的右移分配
x>>=y
按位AND赋值
x和=y
按位异或赋值
x ^=y
按位OR赋值
x |=y
逻辑与赋值
x&&=y
逻辑OR赋值
x||=y
Nullish合并赋值
x??=
从右到左 条件(三元)运算符
x?个?是:z
[11]
从右到左 箭头
x=>y
[12]
不适用 收益率x
产量*x
价差
…x个
[13]
1:逗号 从左到右 逗号运算符
x、 年

笔记:

  1. 操作数可以是任何表达式。
  2. “右侧”必须是标识符。
  3. “右手边”可以是任何表达式。
  4. “右侧”是一个以逗号分隔的列表,其中包含优先级大于1的任何表达式(即非逗号表达式)。的构造函数新的表达式不能是可选链。
  5. 操作数必须是有效的赋值目标(标识符或属性访问)。其优先权意味着新Foo++(新Foo)++(语法错误)而不是新(Foo++)(TypeError:(Foo++)不是构造函数)。
  6. 操作数必须是有效的赋值目标(标识符或属性访问)。
  7. 操作数不能是标识符或私有财产访问。
  8. 左侧不能优先于14。
  9. 操作数不能是逻辑OR||或逻辑AND&&未分组的运算符。
  10. “左侧”必须是有效的分配目标(标识符或属性访问)。
  11. 关联性是指后面的两个表达式?隐式分组。
  12. “左侧”是单个标识符或带括号的参数列表。
  13. 仅在对象文字、数组文字或参数列表内部有效。

第17组和第16组的优先级可能有点模糊。这里有几个例子需要澄清。

  • 可选链接总是可以替代其各自的语法而不具有可选性(除非是禁止使用可选链接的一些特殊情况)。例如,任何接受a?。b也接受a.b公司反之亦然a?。(),a()等。
  • 成员表达式和计算成员表达式总是可以相互替换的。
  • 调用表达式和导入()表达式总是可以相互替换的。
  • 这就留下了四类表达式:成员访问、,新的带参数、函数调用和新的没有参数。
    • 成员访问的“左侧”可以是:成员访问(a.b.c公司),新的带参数(新建a()。b)、和函数调用(a()。b).
    • 的“左侧”新的with参数可以是:成员访问(新a.b())和新的带参数(新建a()()).
    • 函数调用的“左侧”可以是:成员访问(a.b()),新的带参数(新建a()())、和函数调用(a()()).
    • 的操作数新的没有参数可以是:成员访问(新a.b),新的带参数(新建a())、和新的没有参数(新的新的a).