【ES6 教程】01—新的ES6語法:JavaScript let 聲明塊作用域變量

JavaScript let 關(guān)鍵字簡介
let variable_name;
在JavaScript中,塊是由大括號來表示{},例如,if else, for,do while,while,try catch等:
if(condition) {// inside a block}
請參閱以下示例:
let x = 10;if (x == 10) {let x = 20;console.log(x); // 20: reference x inside the block}console.log(x); // 10: reference at the begining of the script
腳本的工作原理:
首先,聲明一個變量x并將其值初始化為 10。
其次,x在if塊內(nèi)聲明一個同名的新變量,但初始值為 20。
第三,輸出塊x內(nèi)和if塊后 變量的值。
因為let關(guān)鍵字聲明了一個塊范圍的變量,塊x內(nèi)的變量if是一個新變量,它隱藏了x在腳本頂部聲明的變量。因此,控制臺x中的值為20。
當(dāng) JavaScript 引擎完成執(zhí)行if塊時,塊x內(nèi)的變量if超出范圍。因此, 塊x后面的變量的if 值為 10。
JavaScript let 和全局對象
當(dāng)你使用var關(guān)鍵字聲明一個全局變量時,你將該變量添加到全局對象的屬性列表中。對于 Web 瀏覽器,全局對象是window. 例如:
var a = 10;console.log(window.a); // 10
但是,當(dāng)你使用let關(guān)鍵字聲明變量時,該變量不會作為屬性附加到全局對象。例如:
let b = 20;console.log(window.b); // undefined
for 循環(huán)中的 JavaScript let 和回調(diào)函數(shù)
請參閱以下示例。
for (var i = 0; i < 5; i++) {setTimeout(function () {console.log(i);}, 1000);}
該代碼的目的是每秒向控制臺輸出 0 到 4 之間的數(shù)字。但是,它會輸出該數(shù)字5五次:
55555
在這個例子中,變量i是一個全局變量。在循環(huán)之后,它的值為 5。當(dāng)回調(diào)函數(shù)被傳遞給setTimeout()函數(shù)執(zhí)行時,它們引用i與值 5相同的變量。
在 ES5 中,你可以通過創(chuàng)建另一個作用域來解決此問題,以便每個回調(diào)函數(shù)引用一個新變量。并且要創(chuàng)建一個新的作用域,你需要創(chuàng)建一個函數(shù)。通常,你可以按如下方式使用IIFE模式:
for (var i = 0; i < 5; i++) {(function (j) {setTimeout(function () {console.log(j);}, 1000);})(i);}
輸出:
01234
在 ES6 中,let關(guān)鍵字在每次循環(huán)迭代中聲明一個新變量。因此,你只需將var關(guān)鍵字替換為let關(guān)鍵字即可解決問題:
for (let i = 0; i < 5; i++) {setTimeout(function () {console.log(i);}, 1000);}
為了讓代碼完全 ES6 風(fēng)格,可以使用如下箭頭函數(shù):
for (let i = 0; i < 5; i++) {setTimeout(() => console.log(i), 1000);}
請注意,你將在后面的教程中了解有關(guān)箭頭函數(shù)的更多信息。
重新申報
該var關(guān)鍵字允許你重新聲明變量而不會出現(xiàn)任何問題:
var counter = 0;var counter;console.log(counter); // 0
但是,使用let關(guān)鍵字重新聲明變量將導(dǎo)致錯誤:
let counter = 0;let counter;console.log(counter);
這是錯誤消息:
Uncaught SyntaxError: Identifier 'counter' has already been declared
JavaScript let 變量和提升
讓我們檢查以下示例:
{console.log(counter); //let counter = 10;}
此代碼導(dǎo)致錯誤:
Uncaught ReferenceError: Cannot access 'counter' before initialization
在此示例中,counter在聲明變量之前訪問該變量會導(dǎo)致ReferenceError, 你可能認(rèn)為使用let關(guān)鍵字的變量聲明不會提升,但會提升。
實際上,JavaScript 引擎會將let關(guān)鍵字聲明的變量提升到塊的頂部。但是,JavaScript 引擎不會初始化該變量。
因此,當(dāng)你引用一個未初始化的變量時,你會得到一個ReferenceError。
暫時死亡區(qū)(TDZ)
由let關(guān)鍵字聲明的變量具有所謂的時間死區(qū) (TDZ)。TDZ 是從塊開始到處理變量聲明的時間。
以下示例說明時間死區(qū)是基于時間的,而不是基于位置的。
{ // enter new scope, TDZ startslet log = function () {console.log(message); // messagedeclared later};// This is the TDZ and accessing log// would cause a ReferenceErrorlet message= 'Hello'; // TDZ endslog(); // called outside TDZ}
在這個例子中:
首先,大括號開始一個新的塊作用域,因此,TDZ 開始。
其次,log()函數(shù)表達(dá)式訪問message變量。但是,該log()功能尚未執(zhí)行。
第三,聲明message變量并將其值初始化為10。從塊作用域開始到message變量被訪問的時間稱為臨時死亡區(qū)。當(dāng) JavaScript 引擎處理聲明時,TDZ 結(jié)束。
最后,調(diào)用log()訪問messageTDZ外變量的函數(shù)。
請注意,如果你訪問由letTDZ 中的關(guān)鍵字聲明的變量,你將獲得 a ReferenceError,如下例所示。
{ // TDZ startsconsole.log(typeof myVar); // undefinedconsole.log(typeof message); // ReferenceErrorlet message; // TDZ ends}
注意myVarvariable 是一個不存在的變量,因此,它的類型是undefined。
臨時死亡區(qū)可防止你在聲明之前意外引用變量。
概括
使用let關(guān)鍵字聲明的變量是塊范圍的,沒有初始化為任何值,也沒有附加到全局對象。
使用let關(guān)鍵字重新聲明變量將導(dǎo)致錯誤。
使用let關(guān)鍵字聲明的變量的時間死區(qū)從塊開始,直到評估初始化。
學(xué)習(xí)更多技能
請點(diǎn)擊下方公眾號
![]()

