ES6 中的let 和 const


  1,塊級作用域。這里想說的是,在一個塊{}中,使用const或let 聲明一個變量,這個變量將統治整個塊(consumes the entire scope),無論你在塊的什么地方聲明這個變量。就算,你是在塊的底部聲明了一個變量, 但是這個變量的作用域,實際上從塊的起始部位開始算起,一直到塊的結束,存在着某種意義上的變量提升。

if(true) {
    // data 變量的作用域從這里開始
    console.log(1);
    console.log(2)

    let data = new Date();
    // data 變量的作用域在這里開始
}

  變量存在提升,這也就意味着,我們有可能無意地使用了后面聲明的變量,尤其是當變量作用域外部有一個和它重名的變量時

let data = 1;

if(true) {
    console.log(data);
    console.log(1);
    console.log(2)

    let data = new Date();
}

  運行這段代碼,報錯了。剛開始的時候,以為第一行的data 讀取的是外部的變量data(1), 因為內部的data 變量還沒有聲明。其實不是,只要在塊中聲明了變量,這個變量將統治整個塊。第一行的console.log 讀取的是塊中最后一行聲明的變量。盡管能讀取變量,但不能使用這個變量。在一個作用域中,在let 或const 變量聲明之前,使用這個變量,將拋出引用錯誤。能夠讀取,但不能使用變量的區域就是暫存死區。在一個作用域中聲明一個變量,暫存死區,指的就是作用域開始位置,到變量聲明位置結束,引用暫存死區中的變量就會拋出引用錯誤。

  2,const 指的是不能重新賦值, 而不是值不能改變。Constants can not be reassigned. Constants are not immutable. 

  一定要區分值和變量。5,false,  {name: 'sam'} 就是值。變量,是需要聲明的,let a;  它其實是在內存中開辟了一個空間,用於保存東西。變量和值是相互獨立的。可以聲明一個變量,不給它值,那這個變量就什么都不能做。也可以只寫一個值,不賦值給任何變量,但這個值只能用一次。當把一個值賦給一個變量的時候,它們有了關系,產生了綁定,變量名和值綁定到一起了,這叫assigin. const 指的就是這一塊內容。值能不能改變,只關系值本身,它不關系和變量的關系。數字5,它就不能再改變了, 但對象就可以改變。

   3, let 和 const 在for 循環中使用 

  let 聲明的變量只在for 的循環體中有效,循環結束后 變量就消失了, 同時const 也可以在for 循環中聲明變量,但是不能用於 常規的for 循環中。所謂的常規for 循環就是for(let i =0; i < 10; i++) 的格式。

  在使用for 循環的時候,每一次的迭代都會重新聲明一個變量。像for(let i = 0; i < 10; i++); 這樣使用時,i 變量聲明了10次,只不過每一次迭代給i 賦值不一樣而已,並且變量只在循環體中使用。 我們可以這樣理解: 第一次迭代的使用,聲明了一個變量i, 賦值為0, 0 < 10, 然后執行循環體,執行完之后i++ 變成了1. 這一次迭代就結束了,這個i 的使命就完成了。然后進行第二次迭代,這時重新聲明一個變量i, 不過這次給他賦值為1,1 < 10 繼續執行循環體,然后加1. 這次迭代又結束了,這個i 也完成了使命,消失了。第三次迭代進行同樣的操作,聲明一個全新的變量i,執行循環體之類的,直達整個循環結束。

  對於for 循環來說,每一次的迭代都是重新聲明一個全新的變量i,只是賦的值是上一次迭代完成時的值,這樣的話,循環體內獲取到的i, 每次也都是全新的變量i,而不是像使用 var 聲明時得到的是全局變量,並且,每一次迭代完成后,i 變量就消失了。

let funs = [];

// 使用var 聲明循環變量i
for (var i = 0; i < 10; i++) {
    funs.push(function(){
        console.log(i);
    })
}
// funs.forEach(item => item());  // 輸出10個10

// 改為使用let 聲明循環變量
let funss = [];

for (let i = 0; i < 10; i++) {
    funss.push(function(){
        console.log(i);
    })
}

funss.forEach(item => item());  // 輸出0, 1, 2, 3, 4, 5, 6, 7, 8, 9

  除了常規的for 循環之外,還有for-in 和for-of 操作, 原理都是一樣的,他們每一次的迭代都是重新聲明一個全新的迭代對象,而不是給原來聲明的迭代對象賦新值, 循環體內獲取到的都是當前迭代對象的值。

let funcs = [];
let arr = [1, 2, 3];
// for-in 循環, 數組是不建議使用for-in ,這里只是簡單的演示
for (let key in arr) {
funcs.push(function() {
        console.log(key);
    });
}
funcs.forEach(function(func) {
    func(); // 輸出0, 1, 2
});

// 使用for-of 
funcs = [];
for (let key of arr) {
    funcs.push(function() {
        console.log(key);
    });
}

funcs.forEach(function(func) {
    func(); // 輸出1, 2,3
});

  現在看一下const, const 也可以使用在for循環中。最簡單的就是把上面的三個for 循環中的let 都轉換為const.  for (const i = 0; i < 10; i++) {};   for (const key of arr) {} , for (const key in arr) {} . 這時你會發現第一種常規for 循環報錯了。看一下第一次迭代就知道了。聲明了一個 變量i, 賦值為0。 但這里使用const, 也就意味着i 在聲明之后,就不能再改變了。好了,0 < 10, 執行循環體,然后  加1,報錯了,i 不能變化了。一次迭代都沒有走完,就報錯了,說明,在使用常規for 循環時, const  不能用來聲明變量。

  再來看一下,for-of, for-in, 沒有問題,因為每一次的迭代都會聲明一個全新的key, 所有的賦值都是給一個新的變量賦值,而沒有改變原來的值。那使用let 和 const 有什么區別嗎? 當然有了,還是在於const  聲明的變量不能重新賦值了,所以如果for-in 或for- of 中使用const 聲明了變量( 如key), 循環體中,就不能給key 賦新值了,如果使用let ,那就無所謂了,想干什么就干什么。只不過for-in 或for-of 中,我們很少改變key 值,所以他們在實際使用時就沒有什么區別了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM