Like Sunday, Like Rain - JavaScript运算符优先级

“JavaScript⾥的不少奇技淫巧,都来⾃于对运算符的灵活使⽤。”html

说到运算符的优先级,咱们每每会想到一张见过无数次却历来没背下来的表。由于没背下来, 因此每每会认为它很简单,只要拿不许的时候去看看就好。我曾经也是这么认为的,直到在一个明媚的下午,我对着这张遍,遇到了几个问题。我才发现我其实并无把它搞定。express

《如晴天,似雨天》但愿你也能有一个阳光明媚的下午,来解开心中的这些困惑。bash

1 运算符基础

咱们先看一下完整的JavaScript运算符优先级表(文章最后,移动端锚点连接很差用,手滑下去吧)框架

这张表说明了两个问题:ecmascript

1.1 优先级: 优先级高的运算符最早被执行

问题: 1 || 1 ? 2 : 3 ; 
    答案:2  
    解析:||的优先级高
       至关于: (1 || 1 )? 2 : 3 
       而不是:  1 || (1 ? 2 : 3 )
复制代码

1.2 关联性: 运算符执行时的方向。是从左向右,仍是从右向左

问题:+function (){var a = b = 1;}();
         console.log(b);  
         console.log(a); 
    答案:1   error
    解析:赋值从右到左,var a = b = 1因此至关于
         b = 1;
         var a = b;
         那有同窗可能会问,为何不是?
         var b = 1;
         var a = b;
         还记得变量提高吗?var a = b = 1;在变量提高的时候,只会把a去声明,并不会执行赋值中的b。
         因此要想把b也声明了就须要按照语法 var a=1 , b ;
复制代码

如今咱们仔细把优先级的题改一下ide

1 || fn() && fn() 
复制代码

MDN上写的是优先级高的运算符最早被执行,咱们都知道 ||是短路的,后边不会执行。那么这个最早被执行的含义是什么呢?函数

1.3 短路:

  • && 运算符的短路(a && b):若是a为假,b就不用执行了
  • | | 运算符的短路(a || b):若是a为真,b就不用执行了
问题:1 || fn() && fn() 
    答案:1  fn不会执行
    解析:就是利用&&运算符的短路原理啊。
复制代码

讲到这有些同窗会以为很简单啊,就是这样啊,看到短路后边就不用算了啊。也有的同窗可能会有点懵,不是说好了, 优先级高的先被执行吗?明明&&的优先级高啊。哈哈,别吵吵,咱们一块儿看下一题。学习

问题:var a = 42;
         var b = "foo";
         var c = 0;

         c || b ? a : b ;  //  42
           
复制代码

刚才说短路的同窗可能会说仍是要参考优先级。刚才说优先级的同窗可能一脸懵逼,静静地不想说话。那么咱们开始今天的学习吧。ui

2 绑定

定义:运算符的优先级高先执行,并非真正的执行,而是更强的绑定。spa

咱们用上面来两个问题

1 || fn()  && fn()   //  &&的优先级高,因此将后边的绑定
    1 ||(fn() && fn())  //  因此至关于1 和(fn() && fn())的值去逻辑或
    1 ||(fn() && fn())  //  咱们查表,逻辑或从左到右执行。
    1 ||(fn() && fn())  //  左执行,1是真值,因此短路,后边不执行
复制代码
问题: var a = 42;
          var b = "foo";
          var c = 0;
          c || b ? a : b ;  
    答案:42
    解析:c || b ? a : b ;     //查表  条件运算符权重是4,逻辑与符权重是6,因此逻辑与有更强的绑定
         (c || b )? a : b ;   //(c || b )至关于条件运算符里的条件
         (c || b )? a : b ;   //(c || b )值是0 ,因此值是 a 
复制代码

好,咱们在作两题巩固一下

问题: var a = 5;
          var b = 5;
          var c = 5+a+++b;
          [ a , c ]
    答案: [6, 15]
    解析: b = 5+a+++b;          //查表  后置递增权重17 前置递增权重16
          b = 5 +(a++)+ b;    //++优先级更高,因此和绑定a绑定在一块儿
          b = 5 +(a++)+ b;    //根据语法后置递增先执行语句,后递增
          b = 5 +(a++)+ b;    //执行语句时a是5,因此b是15
          b = 5 +(a++)+ b;    //a在进行自增,获得6
复制代码
问题: var a = 5;
          var b = 5;
          var c = ++a-b;
          [ a , c ]
    答案: [6, 1]
    解析: var c = ++a-b;        //查表  前置递增权重和一元减权重都是16,从左往右执行
          var c = ++a-b;        //根据语法前置递增先递增,后执行语句 a = 6
          var c = ++a-b;        //执行语句时a是6,因此b是1
复制代码

看到这,同窗们可能恍然大悟,就这么回事啊。别急,咱们来看下一题。 要解决这个问题,须要咱们理解下一节的概念。

问题: var a = 42;
          var b = "foo";
          var c = 0;
          a && b || c ? c || b ? a : c && b : a  
复制代码

3 关联

定义:运算符的关联性去定义表达式的处理方向

来,用题说话

问题:a && b && c 的执行顺序
    解析:(1)两个运算符都是&&,权重同样。因此这个时候就要看关联性。
         (2)查表 &&的关联性是从左到右
         (3)因此表达式应该是 ( a && b ) && c
复制代码
问题:a ? b :c ? d : e 的执行顺序
    解析:(1)两个运算符都是条件运算符,权重同样。因此这个时候就要看关联性。
         (2)查表条件运算符的关联性是从右到左
         (3)因此表达式应该是  a ? b :(c ? d : e )
复制代码

好了,如今咱们就能够轻松解决上面那个问题啦。

问题: var a = 42;
          var b = "foo";
          var c = 0;
          a && b || c ? c || b ? a : c && b : a 
    答案: 42
    解析:(a && b) || c ? c || b ? a :(c && b) : a    //首先查表逻辑与权重是6最高
         ((a && b) || c) ? c || b ? a :(c && b) : a  //而后是逻辑或
         ((a && b) || c) ? (c || b ? a :(c && b)) : a  //两个条件运算符,权重同样。关联性从右到左

复制代码

啊、、有没有很开心 最后的最后,咱们来说一个释疑

4 释疑

哈哈,释疑顾名思义就是解释调疑惑的地方,那最好的办法就是加()。

若是你可以熟练运用优先级/关联的规则,你的代码能更简洁,许多框架都是这样写的,很是漂亮。

可是你要叫不许,那就加()吧,千万别逞能,美其名曰有助于代码的可阅读性。

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

参考:

相关文章
相关标签/搜索