1. 程式人生 > >ES6隨筆--聲明變量

ES6隨筆--聲明變量

數據 基本類型 轉換 IT 提升 重復 -- cee RR

ES6隨筆--聲明變量

let命令

  • 所聲明的變量只在其所處代碼塊內有效;

    {let a = 10};
    alert(a);  // ReferenceError: a is not defined
    
    {let a = 10;
     alert(a);} //10
  • for循環中,for關鍵字後面跟的設置循環變量語句和後面循環體內部語句是父作用域和子作用域的關系;

    var arr = [];
    for (let i = 0; i < 5; i++) {
      arr[i] = function () {
        let i = 10;
        console.log(i);
      };
    }
    arr[3](); // 10
    
    for (let i = 0; i < 5; i++) {
      arr[i] = function () {
        console.log(i);
      };
    }
    arr[3](); // 3
  • let聲明的變量不會提升;

    for (let i = 0; i < 5; i++) {
      console.log(x + i);
      var x = 10; // NaN, 11, 12, 13, 14; 第一次循環變量未初始化
    }
    for (let i = 0; i < 5; i++) {
      console.log(x + i);
      let x = 10; // ReferenceError: x is not defined
    }
  • 在代碼塊內,let聲明變量之前,該變量不可用,即使是在父作用域有同名變量也不行,形成“暫時性死區(TDZ)”
    ```
    var arr = [];
    for (let i = 0; i < 5; i++) {
    arr[i] = function () {
    console.log(i);
    let i = 10;
    };
    }
    arr3; //ReferenceError: i is not defined
    //換成var 就不會出錯了:輸出undefined.

```

  • let不允許在同一個作用域內,重復聲明同一個變量;

    for (let i = 0; i < 5; i++) {
      let a = 3;
      let a = 2;      //Identifier ‘a‘ has already been declared 
    } 

js中原來並沒有塊級作用域的概念,一方面使用var聲明的變量存在提升現象,另一方面var在非函數作用域內聲明的變量都是全局變量,在循環中可能造成混淆引用。

let命令一定程度上規避了這些問題,相當於在js中引入了塊級作用域的概念。

const聲明一個只讀的常量

  • 聲明常量時必須立即初始化賦值;
  • let相似,const
    聲明只在塊級作用域內有效,不存在提升現象,也不允許在同一個作用域內重復聲明。
  • const聲明的基本類型值可以認為是常量不會改變,但如果聲明一個引用類型值,其實際凍結的是這個引用(指針)而不是引用類型值本身。比如數組或對象,const聲明指針後指針不能再改變,不能再給指針賦值,但可以在其指向的對象/數組本身加以操作。
  • 如果要凍結對象,使用Object.freeze()方法。

    const a = Object.freeze({});
    //下面操作不生效,嚴格模式會報錯
    a.prop = "foo";

在ES6中,聲明變量由原來的varfunction,增加到var/function/let/const/import/class六種;

變量的解構賦值

解構賦值可以以數組、對象和基本包裝類型的對象等形式。

數組形式

  • 只要賦值語句的等號前後模式匹配,能夠自動解構賦給對應變量對應的值,如果沒有對應值則為undefined; 在數組中,...foo代表“剩下的值”組成的數組,必須放在最後;

    var [a, b, c, ...d] = [1, 2];
      console.log(a);  // 1
      console.log(b);  // 2
      console.log(c);  // undefined
      console.log(d);  // []
  • 如果等號左邊是數組結構,只要等號後面的數據結構具有iterator接口,就能夠按照數組解構賦值;否則會報錯:

    let[a] = 1; //TypeError: 1 is not iterable
    let[b] = null; //TypeError: null is not iterable
    let[c] = undefined; //TypeError: undefined is not iterable
    let[d] = {}; //TypeError: {} is not iterable
  • 解構賦值也允許指定默認值,只有在賦值對應的位置嚴格等於undefined時默認值才會生效;如果默認值是表達式則只有在用到的時候才會求值;

對象形式

  • 解構賦值還可以用於對象:對象中的屬性沒有一定的順序,所以在賦值時等號左、右要有完全一致的屬性名才能取到值,否則就是undefined;

    let obj = {prop1:p1, prop2:p2} = {prop1:"first", prop2:"second"};
    // 屬性名還是對象的屬性名,變量被賦值;
      console.log(obj[prop1]);  // ReferenceError: prop1 is not defined
      console.log(obj["prop1"]); // "first"
      console.log(obj[p1]); // undefined
      console.log(p1); // "first"
    // 屬性名同時也作為變量被賦值
    let obj = {prop1, prop2} = {prop1:"first", prop2:"second"};
      console.log(obj[prop1]);  // undefined
      console.log(prop1);  // "first"
      console.log(obj["prop1"]); // "first"
  • 可以轉換為基本包裝類型對象的基本類型的值,也可以用於解構賦值,包括數值、布爾值、字符串;(解構賦值的等號右邊如果不是對象或數組,就先轉換成對象,nullundefined不能轉為對象,用於對象形式解構會報錯)
  • 盡量不用圓括號,因為容易導致歧義;至少在賦值語句的模式部分不能使用圓括號;

變量解構賦值的用途

  • 變量值互換;
  • 函數返回的多個值可以一次取出賦給對應變量;
  • 函數參數定義和默認值;
  • 提取JSON數據;
  • 遍歷map結構(for...of循環遍歷配合解構賦值);
  • 輸入模塊的指定方法;

ES6隨筆--聲明變量