ES6 --- 新的變數宣告方式 let 與 const 解析

王小端coder發表於2019-03-29


let

  • let 宣告的變數只在 let 命令所在的程式碼塊內有效。

小例1:

{
    let tmp = 5;
    console.log(tmp); // 5
}

console.log(tmp); // Uncaught ReferenceError: tmp is not defined
複製程式碼

let 宣告的變數只在 let 命令所在的程式碼塊內有效, 在程式碼塊之外無效

const

  • const 宣告一個常量(所謂常量就是物理指標不可以更改的變數),宣告之後不允許改變。意味著,一但宣告必須初始化,否則會報錯。

小例:

const I_MAX = 9999999;
console.log(I_MAX); // 9999999

const I_MIN; // Uncaught SyntaxError: Missing initializer in const declaration
console.log(I_MIN);
複製程式碼
  • const 除了不能改變物理指標的特性,其他特性和 let 一樣。

let const var 的區別

  • let 是在程式碼塊內有效,var 是在全域性範圍內有效。

小例:

{
    var temA = 'A';
    let temB = 'B'
}
console.log(temA); // A
console.log(temB); // Uncaught ReferenceError: temB is not defined
複製程式碼

temA和temB都宣告在程式碼塊裡面,temA是由var宣告,在外部可以直接訪問,temB是由let宣告,在外部不可直接訪問,提示錯誤:temB is not defined

  • let 宣告的變數不存在變數提升。

小例:

temA = 'A';
temB = 'B'; // Uncaught ReferenceError: temB is not defined

console.log(temA); // A
console.log(temB);
        
var temA;
let temB;
複製程式碼

var 宣告的變數存在變數提升,所以temA在賦值語句下面宣告,沒有問題;let 宣告的變數不存在變數提升,所以temB在賦值語句下面宣告,提示錯誤:temB is not defined

  • let 只能宣告一次變數 var 可以宣告多次變數。

小例:

var temA = 'A';
let temB = 'B';
console.log(temA); // A
console.log(temB); // B
var temA = 'C';
let temB = 'D'; // Uncaught SyntaxError: Identifier 'temB' has already been declared
console.log(temA); // C
console.log(temB);
複製程式碼
  • let存在暫時性死區
var tem = 3;

if (true) {
    tem = 5; // Uncaught ReferenceError: tem is not defined
    let tem;
}
複製程式碼

ES6規定如果塊記憶體在let命令,那麼這個塊就會成為一個封閉的作用域,並要求let變數先宣告才能使用,如果在宣告之前就開始使用,它並不會引用外部的變數。

  • let 不會成為全域性物件的一個屬性
var temA = 'A';
console.log(window.temA); // A

let temB = 'B';
console.log(window.temB); // undefined
複製程式碼

var全域性宣告後會作為全域性物件window的一個屬性,而let不會,所以提示undefined

  • const和var的區別,除了const是宣告一個不可更改的常量外,和var的區別和let一致,也就是說上面幾點let和var的區別,同樣也是const和var的區別。

進階用法

  • 在for迴圈中使用let定義變數,只在for迴圈內可以使用。

小例:實現將for迴圈中的i變數,存入arr陣列中,for迴圈結束後,依次輸出。

// ES5的實現
var arr = [];
for(var i = 0; i < 3; i++){
    arr.push(function (){
        console.log(i);
    })
}
arr[0]()  // 3
arr[1]()  // 3
arr[2]()  // 3
複製程式碼

為什麼每次輸入都是3,因為for迴圈每次做的事只是向陣列中存入一個函式,但是函式並沒有立刻執行。i是通過var來宣告的。當for迴圈完,此時i的值是3。當你去執行函式的時候,自然輸出3

ES5的閉包實現
var arr = [];
for(var i = 0; i < 3; i++){
    arr.push((function (arg){
        return function (){
            console.log(arg);
        }
    })(i))
}
arr[0]()  // 0
arr[1]()  // 1
arr[2]()  // 2
複製程式碼

利用ES5的閉包也可以實現,但是程式碼比較複雜,如果用ES6就比較簡單了,看下面程式碼

// ES6的實現
let arr = [];
for(let i = 0; i < 5; i++){
    arr.push(function (){
        console.log(i);
    })
}
arr[0]()  // 0
arr[1]()  // 1
arr[2]()  // 2
複製程式碼

為什麼這樣就能彈出 0,1,2? 其實需要注意個問題,就是這個let i=0;宣告的位置,是在for的()內,那麼你可以理解成,在for的內部就定義了一個i而且是使用let定義的。所以每次迴圈就相當於在當前迴圈的i值的前提下向陣列push的。

總結:var let const 都是宣告變數的關鍵字,var的作用域是函式作用域,在一個函式內利用var宣告一個變數,則這個變數只在這個函式內有效。如果在函式外部宣告一個變數,則這個變數全域性有效,var存在變數提升。const一般用來宣告常量,且宣告的常量是不允許改變的,只讀屬性,因此就要在宣告的同時賦值。const與let一樣,都是塊級作用域,存在暫時性死區,不存在變數宣告提前,不允許重複定義,不會成為全域性物件的一個屬性。


相關文章