ES6學習之 -- let和const命令

  1. let命令
    用來聲明變量,它的用法相似var,可是let命令聲明的變量只在所在的代碼塊中有效。es6

    {
        var a = 1;
        let b = 2;
    }
    
    console.log(a); // 1
    console.log(b); // b is not defined b未定義

    這就說明let定義的變量只在對應的代碼塊中有效。
    一樣的下面是個for循環數組

    for(let i = 0; i < 5; i++){
        // ...
    }
    console.log(i);// i is not defined i未定義

    i只在循環體內有效。
    阮一峯老師的文章中有一個例子咱們看一下而且分析一下瀏覽器

    var a = [];
    for (let i = 0; i < 10; i++) {
      a[i] = function () {
        console.log(i);
      };
    }
    a[6](); // 6

    老師給咱們的分析是這樣子的:數據結構

    上面代碼中,變量i是let聲明的,當前的i只在本輪循環有效,因此每一次循環的i其實都是一個新的變量,因此最後輸出的是6。你可能會問,若是每一輪循環的變量i都是從新聲明的,那它怎麼知道上一輪循環的值,從而計算出本輪循環的值?這是由於 JavaScript 引擎內部會記住上一輪循環的值,初始化本輪的變量i時,就在上一輪循環的基礎上進行計算。
    若是還不理解的話咱們能夠再看一個例子:
    var a = [];
    for (let i = 0; i < 10; i++) {
      let val = i;
      a[i] = function () {
        console.log(val);
      };
    }
    a[6](); // 6

    這時候你就會理解緣由了,就至關於for循環中的執行體,每次的執行都位於一個單獨的代碼塊中。這個val是咱們顯示定義的一個副本,當咱們執行a[6]的時候,他會找到a[6]保存的函數的執行環境下去找這個val,數組a中的每一個元素都位於一個單獨的代碼塊中互不影響。那麼咱們能夠得出一個結論:js引擎會爲咱們for循環中每次循環的代碼塊保存一個副本。
    Nicholas C. Zakas《深刻理解ES6》中也有相關解釋。
    不存在變量提高ide

    console.log(a);// undefined
    console.log(b);// b is not defined
    var a = 1;
    let b = 2;

    暫時性死區
    只要塊級做用域中存在let命令,那麼let聲明的變量就會綁定這個做用域不受外部影響。函數

    var temp = 'hello';
    if(true){
        console.log(temp);// temp is not defined
        let temp;
    }
    緣由就是let綁定了塊級做用域而且let定義的變量不會提高,就是這個地盤跟我同名的都得死。
    隱蔽的死區
    function test(x = y, y = 2) {
        return [x, y];
    }
    test();// 報錯

    緣由是:當執行test()的時候會先將y的值賦給x做爲初始值,但此時y不存在,因此報錯。es5

    function test(x = 2, y = x) {
        return [x, y];
    }
    test();// [2, 2]

    這樣就沒問題了。指針

    總之,暫時性死區的本質就是,只要一進入當前做用域,所要使用的變量就已經存在了,可是不可獲取,只有等到聲明變量的那一行代碼出現,才能夠獲取和使用該變量。

    不容許重複聲明
    let不容許在同一做用域聲明兩個相同的變量。code

    let a;
    var a;//報錯  a已經被聲明瞭
    function fun(params) {
        let params;
    }
    func();//報錯  params已經被聲明瞭
    function test(params) {
        {//內部代碼塊
            let params;
        }
    }
    test();//正常執行  執行函數內部的代碼塊被其中的那個變量佔用了而已

    塊級做用域
    先看一下es5,es5只有全局做用域和函數做用域。對象

    var name = 'Jason';
    function test() {
        console.log(name);
        if(false) {
            var name = 'Nico';
        }
    }
    ==>至關於
    var name = 'Jason';
    function test() {
        var name;//變量提高
        console.log(name);
        if(false) {
            name = 'Nico';
        }
    }
    因此執行test()會打印undefined

    還有就是for循環的時候i的定義被提早

    for(var i = 0; i < 3; i++) {
        console.log(i);
    }
    console.log(i);
    依次打印0 1 2 3

    緣由是i定義被提早,以下:

    var i;
    for(i = 0; i < 3; i++) {
        console.log(i);
    }
    console.log(i);

    es6出現了塊級做用域

    function test() {
        let n = 0;
        if(true) {
            let n = 1;
        }
        console.log(n);
    }
    test();// 0

    外層的塊級做用域不受內層的控制。

    {
        {
            let a = 1;
        }
        console.log(a);//報錯 a未被定義
    }

    外層做用域沒法訪問內層做用域定義的變量

    {
        let a = 0;
        {
            let a = 1;
        }
    }

    內層做用域能夠命名外層已經命名的變量。
    值得提醒的是函數在塊級做用域中的聲明

    function test() {
        console.log('outside');
    }
    (function() {
        if(false) {
            function test() {
                console.log('inside');
            }
        }
        console.log(test());
    })();

    ES5會打印inside字符串,ES6卻會報test is not a function的錯。
    是否是很詫異,爲何ES6沒有打印outside呢?

    緣由是:ES6中容許塊級做用域中聲明函數,可是函數聲明會相似於var提高到全局做用域或者函數做用域頭部,同時函數聲明會提高到塊級做用域頭部,因此上面的代碼就至關於
    function test() {
        console.log('outside');
    }
    (function() {
        var test = undefined;
        if(false) {
            function test() {
                console.log('inside');
            }
        }
        console.log(test());
    })();
    因此纔會報test is not a function的錯誤。

    因此儘可能避免塊級做用域中聲明函數,若是有必要的話可使用函數表達式。

    function test() {
        console.log('outside');
    }
    (function() {
        if(false) {
            let test = function() {
                console.log('inside');
            }
        }
        console.log(test());// outside
    })();
  2. const命令
    用於定義常量,一旦定義必須馬上初始化否則報錯,定義後沒法改變值,改變也會報錯。

    const USER_NAME;//報錯
    const USER_ID = '410100';
    USER_ID = 2;//報錯

    const的做用域與let命令相同:只在聲明所在的塊級做用域內有效
    const命令聲明的常量也是不提高,一樣存在暫時性死區,只能在聲明的位置後面使用。
    const聲明的常量,也與let同樣不可重複聲明。
    const其實保證的是變量存儲的內存地址不得改動,對於簡單的數據類型(數值,布爾,字符串),值就存在內存地址指向的位置,就等同於常量。可是對於數組、對象保存的就是一個指針,只能保證這個指針不被改變。對於內部的數據結構的變化是沒法控制的。

    const ARR = [];
    ARR.push(1);// 能夠執行
    ARR.length = 0;// 能夠執行
    ARR = [];//報錯
    const OBJ = {};
    OBJ.name = 'JASON';// 能夠執行
    OBJ = {};//報錯

    ES6 聲明變量的六種方法:var function let const import class

    頂層對象:瀏覽器中指window Node中指global
    ES5的時候全局變量的賦值與頂層變量的賦值是同一件事。
    ES6改變了這一點除了varfunction還保持原來的方式,新的聲明變量的方法再也不與頂層變量掛鉤。

相關文章
相關標籤/搜索