es6基礎0x002:var、let、const、塊級作用域、暫存死區

0x001 var

  1. 語法

    var varname1 [= value1 [, varname2 [, varname3 ... [, varnameN]]]];
  2. 使用

    var a, b=2 // 聲明多個變量,可以賦值,也可以不賦值
    a=1 // 先聲明,再賦值
  3. var變量提升
    使用var聲明的變量將會被提升到函數的頂部

    console.log(a) // undefined
    var a =2  
    console.log(a) // 2
    console.log(b) //Uncaught ReferenceError: b is not defined...

    以上代碼相當於

    var a
    console.log(a) // undefined
    a=2
    console.log(a) // 2
    console.log(b) //Uncaught ReferenceError: b is not defined...

0x002 let

  1. 語法

    let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];
  2. 使用

    let a, b = 2 // 聲明多個變量,賦值不賦值無所謂
    a = 2 // 聲明之後再賦值
  3. 不再提升

    console.log(a) // Uncaught ReferenceError: a is not defined...
    let a=1 

    注意:猜測, 使用babel翻譯一下代碼發現,只是let變成了var,所以使用babel轉義之後的代碼依舊會提升

  4. 不能重複聲明

    let a=1
    let a=2 // Uncaught SyntaxError: Identifier 'a' has already been declared

0x003 const

  1. 語言

    const name1 = value1 [, name2 = value2 [, ... [, nameN = valueN]]];
  2. 使用

    const a=1, b=2 // 不能省略的值
  3. 不能省略的值

    const c // Uncaught SyntaxError: Missing initializer in const declaration
  4. 不能重複賦值

    const d=4
    d=5 // Uncaught TypeError: Assignment to constant variable.
  5. 可以修改的引用

    const e=[]
    e[0]=0
    console.log(e) //[0]

0x004 塊級作用域

塊級作用域是隨着letconst而來最有用的特性了,在之前的js中,js的作用域是函數級的,由此帶來的幾個臭名昭著的問題:

  • 意外被修改的值

    function varTest() {
      var x = 1;
      if (true) {
        var x = 2;  // 同樣的變量!
        console.log(x);  // 2
      }
      console.log(x);  // 2
    }

    可以使用let避免了

    function letTest() {
      let x = 1;
      if (true) {
        let x = 2;  // 不同的變量
        console.log(x);  // 2
      }
      console.log(x);  // 1
    }
  • 萬惡的for循環和點擊事件

    var list = document.getElementById("list");
    
    for (var i = 0; i < 5; i++) {
      var item = document.createElement("LI");
      item.appendChild(document.createTextNode("Item " + i));
    
      item.onclick = function (ev) {
        console.log("Item " +i + " is clicked.");
      };
      list.appendChild(item);
    }
    console.log(i) // 5

    如果點擊上面,不管點擊哪個,顯示出來的都是Item 5 is clicked.,雖然可以使用閉包解決,但是現在有了更好的方案

    let list = document.getElementById("list");
    
    for (let i = 0; i < 5; i++) {
      let item = document.createElement("LI");
      item.appendChild(document.createTextNode("Item " + i));
    
      item.onclick = function (ev) {
        console.log("Item " +i + " is clicked.");
      };
      list.appendChild(item);
    }

0x005 作用域規則很簡單

  1. {}塊內形成一個作用域,包括ifelsewhileclassdo...while{}function

    {
        const f=6
    }
    console.log(f) // Uncaught ReferenceError: f is not defined
  2. for循環中用let聲明一個初始因子,該因子在每個循環內都是一個新的作用域

    for (let i = 0; i < 10; i++) {
      console.log(i);
    }
    console.log(i) // Uncaught ReferenceError: i is not defined
  3. switch只有一個作用域

    switch (x) {
      case 0:
        let foo;
        break;
        
      case 1:
        let foo; 
        break;
    }
    // Uncaught SyntaxError: Identifier 'foo' has already been declared

0x006 暫存死區-Temporal Dead Zone-TDZ

隨着letconst的引入,也引入了暫存死區的概念。使用var的時候,作用域內(函數作用域),在還沒使用var聲明一個變量的時候,訪問該變量,將會獲得undefined。但是如果使用let,作用域(塊級作用域)內,在還沒使用let聲明一個變量的時候,訪問該變量,將會獲得ReferenceError,從作用域開始到let語句之間,就是暫存死區。

{
 console.log(a) // Uncaught ReferenceError: a is not defined
 console.log(b) // Uncaught ReferenceError: b is not defined
 console.log(c) // undefined
 // 暫存死區
 let a =1
 const b=2
 var c=3
}

注意:猜測, 使用babel翻譯一下代碼發現,只是let變成了var,所以使用babel轉義之後可能不存在暫存死區

0x007 總結

儘量使用letconst,如果希望改變該變量的值,則使用let,如果希望不再改變該變量的值或者引用,則使用const,讓var成爲歷史。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章