ES6-let 與 const


1.let命令?


基本概念

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

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

var 定義的變量要么為全局變量,要么是在函數(shù)之中的局部變量。上述代碼塊中的?a?即為全局變量,所以在代碼塊外也可調(diào)用此變量。而在代碼塊外調(diào)用變量 b 報錯可證明?b?只在定義它的代碼塊中有效。


不存在變量提升和暫時性死區(qū)

ES6 中的?let?命令是不存在變量提升”現(xiàn)象的,變量提升指的是在變量未經(jīng)定義之前便可調(diào)用。

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


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

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

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

當(dāng)你輸入上述代碼卻得到報錯的結(jié)果是不是很疑惑呀,為什第一句代碼沒有把變量 b 定義為一個全局變量呢?

沒錯!“罪魁禍?zhǔn)住?就是 let 命令,因為從當(dāng)前作用域的頭部一直到?let 命令聲明變量?b?之前,b都是不可用的,這在語法上稱為暫時性死區(qū)(temporal dead zone)。

ES6中規(guī)定暫時性死區(qū)let、const不出現(xiàn)變量提升,能夠有效地避免在聲明變量之前就使用它。


重復(fù)定義檢查

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

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


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


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

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


let 用途

下面考慮一種需求:需要動態(tài)往HTML中一個ID為“list”的標(biāo)簽中插入十個li標(biāo)簽,并且每個li標(biāo)簽都帶有一個提示本標(biāo)簽被點擊的點擊事件。

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 循環(huán)完成了上述需求。這時候你會想這個和?let?命令有什么關(guān)系,我換成?var 豈不是也能實現(xiàn)。下面我們來檢驗一下?lián)Q成?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);
}

當(dāng)我們點擊上述代碼生成的?li?標(biāo)簽時,會發(fā)現(xiàn)無論點擊哪個都會打印出“Item 11 is clicked.”。下面我來解釋一下為什么會出現(xiàn)這種情況,因為在?for?循環(huán)中的變量?i?var定義的,在全局范圍內(nèi)都有效,而每個標(biāo)簽被點擊所執(zhí)行的函數(shù)內(nèi)部的?i?都指的是這個全局的?i?。而使用?let?命令時,循環(huán)體的每一次執(zhí)行都產(chǎn)生一個作用域,每次綁定點擊事件時,函數(shù)都能保留當(dāng)前計數(shù)器的數(shù)值和引用。

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


2.const命令


基本概念

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

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

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


原理

變量與內(nèi)存之間的關(guān)系由三部分組成:變量名、內(nèi)存綁定及內(nèi)存地址。const 的實現(xiàn)原理便是在常量名和內(nèi)存地址之間創(chuàng)建一個不可變的綁定。在某些情況下,并非是值不可變的。對于基本類型(數(shù)值,字符串等)而言,常量指向的內(nèi)存地址便保存著實際值。而對于對象、數(shù)組等引用類型,常量指向的只是一個指針,const 只能保證這個指針是不可變的,如下:

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

凍結(jié)對象

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

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


3.建議

1. 一般情況下,使用?const?命令對值進(jìn)行存儲;
2. 當(dāng)一個值容器存儲的值確認(rèn)會被改變時才使用?let?進(jìn)行定義;
3. 不再使用?var

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • let和const let命令 let用法類似var,但是所聲明的變涼,只在let命令所在的代碼塊內(nèi)有效 for循...
    李諾哦閱讀 400評論 0 1
  • let 和 const 命令 let 命令 塊級作用域 const 命令 頂層對象的屬性 gl...
    安小明閱讀 1,041評論 0 0
  • let 命令 塊級作用域 const 命令 頂層對象的屬性 global 對象 let 命令 基本用法 ES6 新...
    嘉奇呦_nice閱讀 1,694評論 0 2
  • let 命令 塊級作用域 const 命令 頂層對象的屬性 global 對象 let 命令 基本用法 ES6 新...
    卞卞村長L閱讀 682評論 0 0
  • var缺陷 1.重復(fù)聲明 2.沒有塊級作用域,只有函數(shù)作用域 let特性 1.不能重復(fù)聲明 2.作用域為塊級 co...
    余生筑閱讀 367評論 0 0

友情鏈接更多精彩內(nèi)容