运算符优先级总结

801 阅读5分钟

前言

最近看到了一道关于运算优先级的面试题,题目如下:

var a = 1;
b = a+++a
console.log(a, b)

要回答这道题,我们需要了解到JavaScript中的三个概念:优先级、结合性、运算顺序。

优先级

什么是优先级呢,以前我们学数学的时候,大家都知道这么一个问题,在一个数学表达式中,先算乘除,再算加减,这种先算哪个后算哪个叫做优先级。运算符的优先级决定了表达式中运算执行的先后顺序,优先级高的运算符最先被执行。

consol.log(1 + 2 * 3) // 1 + 6
// 输出数字7
a=3
console.log(++a == 3) // false

js中一元运算符优先级高于等号运算符,所以上面的例子先运算 ++a 为4 然后判断 4 == 3所以返回false

结合性

我们刚才说过在数学表达式中,先算乘除,再算加减,这种是有优先级的,那么乘和除它的优先级是相等的,当乘除同时存在时,先算乘还是先算除呢?这个是js的处理方式,我们把这个处理方式叫做结合性。严谨一些说就是当一个表达式,存在多个运算符,并且这几个运算符优先级相同时,这种如何计算?结合性决定了拥有相同优先级的运算符的执行顺序。js中存在两种结合性,一种是左结合 一种是右结合。其实就是从左开始计算还是从右开始计算。

例如下面的这个例子上得到布尔类型还是数字类型

var a = 5;
console.log(!a++)
  • 如果这个我们从左到右计算的话,就会先计算 !a,得到一个布尔类型的数据,然后再进行++运算,最终会得到一个数字类型的数据。

  • 如果我们从右到左计算的话,就会先计算a++,得到一个数字类型的数据,然后再进行!的运算,最终会得到一个布尔类型的数据。

!和++都属于一元运算符,当两个一元运算符同时出现时,从右向左运算,即右结合。所以上面的例子会得到一个布尔类型的数据。那么在给大家举个右结合的例子:

x = a ? b : c ? d : e ? f : g

上面的这个例子最终解析为:

x = a ? b : ( c ? d : ( e ? f : g ))

js中遇到三元运算符也是右结合的计算方式。

运算顺序

在js中虽然规定了优先级,也规定了结合性,那么有了优先级和结合性,就可以计算整个表达式,,这只是对一个表达式的计算,,当表达式里面还存在表达式的时候,也就是说这个表达式包含子表达式的时候,那这个时候js是怎么处理的呢?在js中所有的运算,如果这个里面存在表达式的话,那么js永远是从左向右的运行。这个是js的运算顺序。

汇总表

下面的表将所有运算符按照优先级的不同从高(20)到低(1)排列。

优先级 运算类型 关联性 运算符
21 圆括号 n/a(不相关) ( … )
20 成员访问 从左到右 … . …
需计算的成员访问 从左到右 … [ … ]
new (带参数列表) n/a … [ … ]
函数调用 从左到右 … ( … )
可选链(Optional chaining) 从左到右 ?.
19 new (无参数列表) 从右到左 new …
18 后置递增(运算符在后) n/a … ++
后置递减(运算符在后) … --
17 逻辑非 从右到左 ! …
按位非 ~ …
一元加法 + …
一元减法 - …
前置递增 ++ …
前置递减 -- …
typeof typeof …
void void …
delete delete …
await await …
16 从右到左 … ** …
15 乘法 从右到左 … ** …
除法 … / …
取模 … % …
14 加法 从左到右 … + …
减法 … - …
13 按位左移 从左到右 … << …
按位右移 … >> …
无符号右移 … >>> …
12 按位左移 从左到右 … < …
无符号右移 … >>> …
小于等于 ... <= …
大于 ... > …
大于等于 ... >= …
in ... in …
instanceof ... instanceof …
11 等号 从左到右 ... == …
非等号 ... != …
全等号 ... === …
非全等号 ... !== …
10 按位与 从左到右 ... & …
9 按位异或 从左到右 ... ^ …
8 按位或 从左到右 ... | …
7 逻辑与 从左到右 ... && …
6 逻辑或 从左到右 ... || …
5 空值合并 从左到右 ... ?? …
4 条件运算符 从右到左 ... ? ... : …
3 赋值 从右到左 ... = …
… += …
… -= …
… **= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …
… &&= …
… ||= …
… ??= …
2 yield 从右到左 yield …
yield* yield* …
1 展开运算符 n/a ... …
0 逗号 从左到右 … , …

总结

那么说完了优先级,又说完结合性,还说完了运算顺序,那么我们再看开头的例子:

var a = 1;
b = a+++a
console.log(a, b)

js是怎么运行这个这行代码的

  • 首先,js会先去计算b,得到第一步,也就是我们刚才说的运算顺序,b=是一个表达式
  • 第二步,会去计算这个a++,得到结果是1,假设得到的结果为c,即 c的值为1,注意:这个时候a的值已经从1变为2了;
  • 第三步,计算后面的这个a,得到2;
  • 第四步,计算的就是c+2,即 1+2得到3,把这个结果值3传给b,这样就得到总的结果a=2,b=3。

那么大家可以看下面这个面试题,思考下这个结果会是什么呢?

var a = 1;
b = a++ + ++a
console.log(a, b)