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 逗號 從左到右 … , …

參考:

相關文章
相關標籤/搜索