iT邦幫忙

1

ES6 學習筆記_01(let & const)

let基本介紹

在ES6中新增了let與const兩個命令,用法類似於var但是最大的不同在於var作用於全域而let與const作用於塊狀區域中。

var作用全域 :

for(var i=0;i<5;i++){
    //...
}

//即使i是宣告在for當中,卻可以在外部(全域)中呼叫到
console.log(i); // 5

let作用塊狀區域 :

for(let i=0;i<5;i++){
    //...
}

//由於let只作用在塊狀區域中(for)所以在全域的環境中無法呼叫
console.log(i); //i is not defined

var a = [];
for(var i=0;i<5;i++){
    a[i] = () => {
        console.log(i);
    }
}
a[3](); //5

由於i是透過var所建立的變數,代表著它在全域中都有效所以全域變數中只有一個變量i,
也就是說數組a中的所有成員的i都會指向同一個全域的i也就是最後一輪的i值 = 5。

var a = [];
for(let i=0;i<5;i++){
    a[i] = () => {
        console.log(i);
    }
}
a[3](); //3

變量i是由let所宣告的所以i只對本次迴圈有效,每一次循環的i都是一個新的變量,而JaveScript引擎會記錄著上一次迴圈的值並在上一次數著基礎下進行計算,


不存在變量的hoisting

若使用var來宣告變數會發生變量hoisting的現象,在變量被宣告數值之前值為undefinded,而若是使用了let或const來宣告變數一定要在宣告數值之後才能使用否則會爆錯。

//使用var宣告
console.log(foo)  //undefinded
var foo = 2;

//使用let宣告
console.log(bar) //ReferenceError
let bar = 2;

在使用var去宣告變數foo會發生變數hoisting的現象,因為當程式開始運行後變量foo就存在了只是尚未給予他值,所以輸出為undefinded;但若使用let來宣告則不會發生hoisting,代表在宣告他之前便量bar是不存在的。


暫時性死區(temporal dead zone)

只要在區塊作用域中存在let,他所宣告的變量就會綁定這個區域不再受外面影響,而在ES6中規定了若在區塊作用域中存在letconst,這個區塊對這些宣告的變量就形成了封閉作用域,凡是在宣告前就使用就會爆錯。

var tmp = 123;

if(true){
    tmp = "abc" //ReferenceError
    let tmp; //使用let對tmp宣告會使tmp不受到外面var=123的影響
}

暫時性死區對typeof影響

在過去沒有塊狀作用域的概念下,對沒有宣告的變量使用typeof去觀察他的類型都會回傳undefinded,所以在沒有塊狀作用域之前使用typeof是絕對安全的不會爆錯,而在ES6中倒入了letconst,在尚未使用let宣告變量之前使用typeof也會爆錯。

typeof x; // ReferenceError
let x;

ES6所規定的暫時性死區和let,const為了減少運行時發生錯誤而移除了變量hoisting的情況,嚴格規定先宣告再使用。


不允許重複聲明

let不允許在相同作用域中重複地宣告同一個變數。

//Error
function func() {
  let a = 10;
  var a = 1;
}

// Error
function func() {
  let a = 10;
  let a = 1;
}

因此不能在函數內部重新宣告參數

func = (arg) => {
    let arg;
};
func(); //Error

func = (arg) => {
    {
        let arg; //因為對於let arg來說已經是第二集區塊作用域,所以不符合與function相同作用域
    }
};
func(); //不會出錯

const基本介紹

const宣告了一個唯獨的常數,一旦被宣告則常數的值變不能被改變。

const PI = 3.1415;
console.log(PI); //3.1415

PI = 3; // Assignment to constant variable.

由於const宣告的常數值不得被改變,所以在使用const宣告一個常數的時候必須立即給予他數值(初始化)不能留到後面再賦值。

const foo; //SyntaxError: Missing initializer in const declaration

而const的作用域與let相同,只有在宣告所在的塊狀作用域有效。

if (true) {
    const MAX = 5;
}

MAX // Uncaught ReferenceError: MAX is not defined

const同樣不支援常數的hoisting,所以同樣存在暫時性死區,只能在宣告後使用。

if (true) {
    console.log(MAX); // ReferenceError
    const MAX = 5;
}

const的本質

透過const所宣告的常數雖然不能更改他的值,不過他不能被更改的指的是內存的地址所保存的數據不得被更改,對於簡單類型的數據(數值、字串、Boolen),他的值就是指向const所宣告的常數的內存地址所以不得被更動,但對於複合型數據而言(物件、陣列),保存的只是一個指向實際數據的指針,const只能保證這個指針是固定的(總是指向固定的地址,數據結構不可變),但是數據結構內的值是可以改變的。

const foo = {};

foo.prop = 123; //對於foo這個物件中新增屬性是可以的
console.log(foo.prop) // 123

//但是不可將透過const宣告過的常數指向另一個物件
foo = {}; //TypeError: "foo" is read-only

參考資料 :
ECMAScript 6 入门


尚未有邦友留言

立即登入留言