[29] 文法 - 運算子優先序、結合性


keywords:operator precedence,associativity

運算子優先序

在前一章我們介紹到運算式副作用, () 本身無法定義一個新的包裹運算式,不過如果想要達到指定 99 到 b 可以運用
, 述句序列逗號運算子,這個運算子能將多個獨立的運算式述句串成單一個述句

    ex1:

    let a = 98,b;

    b = (a++,a);

    a; // 99

    b; // 99

    ex2:

    let a = 98,b;

    b = a++,a;

    a; // 99

    b; // 98

為何 b 會因為有無 () 值而有所不同? 因為 , 運算子的優先序 ( precedence ) 比 = 運算子還要低,所以 ex2 會被解讀為這樣:

    ( b = a++ ), a;

    而這在上一章有提到, a 會先指定給 b 也就是 98 ,然後 a 做 +1 的動作 

    故 a; // 99

    b; // 98

先來看看 運算子優先序的完整列表

  1. 優先順序數字越高越優先 20 -> 1
  2. 當優先序相同時,使用相依性決定運算方向。範例如下:

     a = b = 5;
    
     左相依性 ( Left-associativity ) ,表示處理順序為從左至右 ( a OP b ) OP 5
    
     右相依性 ( right-associativity ) 表示處理順序為從右至左 a OP ( b OP 5 )
    
     而賦值運算符 ( Assignment operators ) 為右相依性
    
     a 和 b 的預期結果為 5,因為賦值運算符 ( Assignment operator ) 為右相依性,因此從右至左返回值
    
     一開始 b 被設定為 5,接著 a 也被設定為 5。
    

&& 優先序比 || 還要高

    let a = 98;

    let b = 'xyz';

    let c = false;

    let d = a && b || c ? c || b ? a : c && b : a;

    這什麼東西 😱 😱 😱

第一個部分先來看 a && b || c 到底會是什麼

    false && true || true; // true

    ( false && true ) || true; // true

    false && (true || true); // false

    所以 && 運算子會被先估算,其次是 || 運算子

不過有可能是出自於左到右的處理順序嗎? 試著反轉運算子的順序

    true || false && false; // true

    ( true || false ) && false; // false

    true || (false && false); // true

結果是不會, && 還是會被先估算,所以證明是運算子優先序決定先後順序

短路 ( short circuiting )

  • 對於 && 或 || 運算子來說,如果左手邊的運算元足以決定該運算的結果,那右手邊的運算元就不會被估算。因此產生短路 ( short circuited )
  • 舉例來說, a && b 如果 a 是 falsy 的,b 就不會被估算,因為 && 運算的結果已然確立,沒有必要再檢查 b
  • a || b 中如果 a 是 truthy 的,此運算的結果就已經確定,沒理由再去檢查 b

      function f1( opts ) 
    
        if ( opts && opts.cool ){ .. }
    
      }
    
      如果 opts 未設定 ( 又或者不是一個物件 ),運算式 opts.cool 就會擲出一個錯誤。
    
      opts 的測試失敗加上短路,意味著 opts.cool 根本不會被估算,因此不會有錯誤產生!
    
      ----------------------------------------------
    
      同樣的 || 也可以有短路的行為:
    
      function f1( opts ){
    
        if ( opts.cache || f2() ) { .. }
    
      }
    
      先檢查 opts.cache 如果它存在就不會呼叫 f2() 函式,避免了可能白費的工夫
    

結合性 ( associativity )

根據運算子優先序的完整列表有寫道,如果優先序相同時,使用相依性決定運算方向

    a && b && c 

    這樣的運算式中,歸組動作會隱含地發生,意味著 a && b 與 b && c 中會有一組先被估算

    根據運算子優先序的完整列表

    && 及 || 是左結合

    ? : 及 = 是右結合

先前的例子:

    let a = 98;

    let b = 'xyz';

    let c = false;

    let d = a && b || c ? c || b ? a : c && b : a;

優先順序:

    && 為 6 從左至右

    || 為 5 從左至右

    ?: 為 4 從右至左

    >> (a && b) || c ? c || b ? a : (c && b) : a;   

    >> ((a && b) || c) ? (c || b) ? a : (c && b) : a;  

    >> ((a && b) || c) ? ((c || b) ? a : (c && b)) : a;

    ---------------拆解開始---------------------------

    1. ( 'xyz' || c ) ? ((c || b) ? a : false ) : a;  先計算 && 的運算式

    2. 'xyz ? ( 'xyz' ? a : false ) : a;  再計算 || 的運算式

    3. 'xyz' ? 98 : 98;  最後計算 ?: 的運算式

    4. 98

結語:

  • 我們應該在程式中搭配使用運算子優先序 / 結合性以及 () 手動歸組
  • 如果能藉以寫出較短且較清楚的程式碼,就使用運算子優先序或結合性,在適合的地方使用 () 手動歸組來使程式碼更清楚明白,降低混淆
#operator precedence #associativity







你可能感興趣的文章

Quick Tutorial of Linux and Workstation

Quick Tutorial of Linux and Workstation

滲透測試基本技術 第三章 (005)

滲透測試基本技術 第三章 (005)

金魚系列、RWD 中

金魚系列、RWD 中






留言討論