ES6-let 與 const


1.let命令 

基本概念

let語法類似於var,不同點在於let定義的變量只在定義它的代碼塊中有效。

{
var a = 1;
let b = 2;
}
a // 輸出1
b // 報錯 Uncaught ReferenceError: b is not defined

var 定義的變量要麼爲全局變量,要麼是在函數之中的局部變量。上述代碼塊中的 即爲全局變量,所以在代碼塊外也可調用此變量。而在代碼塊外調用變量 b 報錯可證明 只在定義它的代碼塊中有效。


不存在變量提升和暫時性死區

ES6 中的 let 命令是不存在變量提升”現象的,變量提升指的是在變量未經定義之前便可調用。

console.log(a);
var a = 1; 
// undefined


console.log(b); 
let b = 2;
// Uncaught ReferenceError: b is not defined

上述代碼,使用 var 定義的變量 a 發生變量提升,在腳本程序運行時變量已經存在了,只是還未定義值,所以輸出 undefined。而變量 b 在未定義之前調用打印 的代碼會報錯,表明使用let 命令定義的變量是不存在變量提升的。

b = 3; 
let b = 2;
// Uncaught ReferenceError: b is not defined

當你輸入上述代碼卻得到報錯的結果是不是很疑惑呀,爲什第一句代碼沒有把變量 定義爲一個全局變量呢?

沒錯!“罪魁禍首” 就是 let 命令,因爲從當前作用域的頭部一直到 let 命令聲明變量 之前,b都是不可用的,這在語法上稱爲暫時性死區(temporal dead zone)

ES6中規定暫時性死區letconst不出現變量提升,能夠有效地避免在聲明變量之前就使用它。


重複定義檢查

相同作用域內,var 可以讓同一個變量名在同一個作用域裏被定義多次,而 let 則不允許。以下是幾個例子。

{
let a = 1;
var a = 2;
}


{
let b = 2;
let b =3;
}


function test(argument){
let argument = 4;
}
test();

上述三塊代碼均會報出變量名已經聲明的錯誤。


let 用途

下面考慮一種需求:需要動態往HTML中一個ID爲“list”的標籤中插入十個li標籤,並且每個li標籤都帶有一個提示本標籤被點擊的點擊事件。

var list = document.getElementById('list');
for( let i=1;i<=10 ;i++){
let item = document.createElement('li');
item.appendChild(document.createTextNode('Item '+i));
item.onclick = function(e){
console.log('Item '+i+' is clicked.');
};
list.appendChild(item);
}

上述代碼利用 for 循環完成了上述需求。這時候你會想這個和 let 命令有什麼關係,我換成 var 豈不是也能實現。下面我們來檢驗一下換成 var 可行嗎?

var list = document.getElementById('list');
for( var i=1;i<=10 ;i++){
let item = document.createElement('li');
item.appendChild(document.createTextNode('Item '+i));
item.onclick = function(e){
console.log('Item '+i+' is clicked.');
};
list.appendChild(item);
}

當我們點擊上述代碼生成的 li 標籤時,會發現無論點擊哪個都會打印出“Item 11 is clicked.”。下面我來解釋一下爲什麼會出現這種情況,因爲在 for 循環中的變量 var定義的,在全局範圍內都有效,而每個標籤被點擊所執行的函數內部的 都指的是這個全局的 。而使用 let 命令時,循環體的每一次執行都產生一個作用域,每次綁定點擊事件時,函數都能保留當前計數器的數值和引用。

注意:
let、const 命令定義的全局變量不屬於頂層對象的屬性。
let a = 1;
window.a // undefined


2.const命令


基本概念

const 命令用來定義常量,一旦聲明,不可改變。這也意味着聲明變量的同時就需要進行初始化,不可留到以後賦值。

const Max_Age;
Max_Age = 100;
// Uncaught SyntaxError: Missing initializer in const declaration

const 命令與 let 命令一樣:
1.只在聲明的塊級作用域有效;
2.常量不可提升,同樣存在暫時性死區;
3.不可重複聲明。


原理

變量與內存之間的關係由三部分組成:變量名、內存綁定及內存地址。const 的實現原理便是在常量名和內存地址之間創建一個不可變的綁定。在某些情況下,並非是值不可變的。對於基本類型(數值,字符串等)而言,常量指向的內存地址便保存着實際值。而對於對象、數組等引用類型,常量指向的只是一個指針,const 只能保證這個指針是不可變的,如下:

const obj = {};
obj.item = 456;
obj.item; // 輸出456
obj = {}; // Uncaught TypeError: Assignment to constant variable.

凍結對象

上述說明當用 const 定義對象時,並不能保證值不可變,下面我們就介紹如何獲取值不可變的對象。除了凍結對象,如果對象的屬性指向的還是對象,那麼這個屬性也該被凍結。如下代碼便可獲取值不可變的對象。

const deepFreeze = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach((key,i) => {
if(typeof obj[key] === 'object')
{ deepFreeze(obj[key]);}
});
};


3.建議

1. 一般情況下,使用 const 命令對值進行存儲;
2. 當一個值容器存儲的值確認會被改變時才使用 let 進行定義;
3. 不再使用 var

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