[28] 文法 - 述句完成值、運算式副作用、區塊


keywords:statement,expression

文法

JavaScript 的語言語法 ( syntax ) 是如何運作的 ( 即它的文法 )

英文文法:

  • 一個句子 ( sentence ) 是表達一個想法用的字詞完整結構,由一個或多個片語 ( phrases 或稱 詞組) 所構成,其中每個都能以標點符號或連接詞來結合
  • 一個片語本身可由更小的片語組成,有些片語不完整無法單獨使用,而有些本身就有意義

程式文法:

  • 述句:句子
  • 運算式:片語
  • 運算子:連接詞或標點符號

      let a = 8 * 3;
    
      let b = a;
    
      b;
    
      以上三行中每一行都是含有運算式的一個述句
    
      其中第一二行扣掉那些 let 稱為指定運算式 ( assignment expressions )
    
      第三行只有運算式 b 稱為運算式述句( expression statement )
    

述句完成值

述句都有完成值,即便值只是 undefined 也算

  • 要確認一個述句的完成值可以在開發人員主控台 ( developer console ) 打入該述句,執行它時主控台會回報最近一次執行的述句完成值
  • let a = 98;  // undefined 指定運算式所產生的是被指定的值,在語言規格裡面的定義中這個 let 述句本身產生的是 undefined
  • 任何正規的 { .. } 區塊都會有一個完成值,它所包含的是最後一個述句或運算式的值

      let b;
    
      if (true) {
    
        b = 88 + 10;
    
      }
    
      // 98 因為 if 區塊的完成值即為 98
    
      換句話說一個區塊的完成值就像是該區塊中最後一個述句隱含的回傳 ( implicit return ) 值
    
  • 如果想要拿到一個述句的完成值或許會想要這樣寫

      let a, b;
    
      a = if (true){
    
        b = 88 + 10;
    
      };
    
      // SyntaxError: Unexpected token 'if'
    
      不過是可以這樣子寫但不建議使用:
    
      a = eval("if (true){  b = 88 + 10;}");
    
      // 98
    
      ES7 有個提案叫做 do expression 可能得運作方式:
    
      a = do {
    
        if (true){
    
          b = 88 + 10;
    
        }
    
      };
    
      a; // 98
    
      最後一個述句的完成值會變成 do 運算式的完成值,而指定給 a
    

運算式副作用

帶有副作用的運算是最常見的例子就是函式呼叫運算式

    function foo(){

      a = a + 1;

    }

    var a = 1;

    foo(); // undefined

    a; // 2

其他帶有副作用的運算式例如:

    let a = 98;

    let b = a++;

    a; // 99

    b; // 98

    a++ 帶有兩個獨立的行為:

    1. 回傳 a 目前的值

    2. 變更 a 本身的值,將之遞增 1

有時候會誤以為可以將 a++ 包裹在一對 () 來封住它的後發副作用

    let a = 98

    let b = (a++);

    a; // 99

    b; // 98

    () 本身無法定義一個新的包裹運算式,不過如果想要達到指定 99 到 b 可以運用

    ,述句序列逗號運算子,這個運算子能將多個獨立的運算式述句串成單一個述句

    let a = 98,b;

    b = (a++,a);

    a; // 99

    b; // 99

    ----------------------------------------------

    let a = 98, b;

    b = (a++,a,a+2);

    a; // 99

    b; // 101

    但其中 () 是必要的,因為運算子的優先序

    運算式 a++ 代表第二個 a 述句運算式會在 a++ 運算式的後發副作用之後被估算,意味著會回傳 99 作為要指定給 b 的值

取決於上下文的規則

區塊

一個常被提到的陷阱:

    [] + {}; // "[object Object]"

    {} + []; // 0     

    🤔 🤔
  • 第一行 {} 出現在 + 運算子的運算式中,所以會被解讀為一個實際的值 ( 一個空 object ),而 [] 會被強制轉型為 '' 所以 {} 也會被強制轉型為一個 string 值 "[object Object]"。
  • 第二行 {} 被解讀為一個獨立的 {} 空區塊,區塊不需要分號來終結它們,所以這裡少了分號並不是個問題,最後 +[] 是一個運算式,它會明確地強制轉型 [] 為一個 number 也就是 0 值。

else if 與選擇性區塊

JavaScript 文法的一個隱藏特徵:沒有 else if 存在
if 與 else 述句接附的區塊若只含單一個述句,就能夠省略它們周圍的 {}

    if (a) f1(a);

    相同文法規則也適用於 else 子句

    if (b) {..} else {..} 後面接著 else 的一個單述句,所以能放 {} 或不放:

    if (b) {..} else ..

    ex:

    let a = '1';

    if ( a === '2' ){ console.log("a"); } else console.log('b'); // b

    else if 也一樣:

    let a ='1';

    if ( a === '2' ){ console.log("a"); } else if (a==='1') console.log('b'); // b
#statement #expression







你可能感興趣的文章

從 Closure 更進一步理解 JS 運作

從 Closure 更進一步理解 JS 運作

JS 與瀏覽器的溝通與網頁事件處理

JS 與瀏覽器的溝通與網頁事件處理

API 是什麼?

API 是什麼?






留言討論