本文學(xué)自阮大神的 let和const命令,文章整理為精簡版。
一屋休、let命令
let
所聲明的變量,只在le
t命令所在的代碼塊
內(nèi)有效备韧。就不做過多介紹了劫樟。
下面通過for循環(huán)來簡要說明下let
:
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
若for循環(huán)中使用var,則a6打印出來的為10织堂;
上面代碼中叠艳,變量i是let聲明的,當(dāng)前的i只在本輪循環(huán)有效易阳,所以每一次循環(huán)的i其實都是一個新的變量附较,所以最后輸出的是6。你可能會問潦俺,如果每一輪循環(huán)的變量i都是重新聲明的拒课,那它怎么知道上一輪循環(huán)的值,從而計算出本輪循環(huán)的值事示?這是因為JavaScript 引擎內(nèi)部會記住上一輪循環(huán)的值
早像,初始化本輪的變量i時,就在上一輪循環(huán)的基礎(chǔ)上進(jìn)行計算肖爵。
不存在變量提升
簡單一句話:若沒有l(wèi)et定義變量卢鹦,那么變量就是未定義的,它所聲明的變量一定要在聲明后使用劝堪,否則報錯冀自。
暫時性死區(qū)
簡單一句話:只要塊級作用域內(nèi)存在let命令揉稚,它所聲明的變量就“綁定”(binding)這個區(qū)域,不再受外部的影響凡纳。
總結(jié)為:在代碼塊內(nèi)窃植,使用let命令聲明變量之前,該變量都是不可用的荐糜。這在語法上巷怜,稱為“暫時性死區(qū)”(temporal dead zone,簡稱 TDZ)暴氏。
不允許重復(fù)性聲明
let不允許在相同作用域內(nèi)延塑,重復(fù)聲明同一個變量。
二答渔、塊級作用域
為什么需要塊級作用域
ES5 只有
全局作用域
和函數(shù)作用域
关带,沒有塊級作用域
,這帶來很多不合理的場景沼撕。
- 第一種場景宋雏,內(nèi)層變量可能會覆蓋外層變量。
- 第二種場景务豺,用來計數(shù)的循環(huán)變量泄露為全局變量磨总。
ES6的塊級作用域
即代碼塊,不再贅述笼沥,記錄一點:塊級作用域的出現(xiàn)蚪燕,實際上使得獲得廣泛應(yīng)用的立即執(zhí)行函數(shù)表達(dá)式(IIFE)不再必要了。
塊級作用域與函數(shù)聲明
ES5 規(guī)定奔浅,函數(shù)只能在頂層作用域和函數(shù)作用域之中聲明馆纳,不能在塊級作用域聲明。
上面兩種函數(shù)聲明汹桦,根據(jù) ES5 的規(guī)定都是非法的
鲁驶。
但是,瀏覽器沒有遵守這個規(guī)定
舞骆,為了兼容以前的舊代碼灵嫌,還是支持在塊級作用域之中聲明函數(shù)。
關(guān)于ES6的塊級作用域與函數(shù)聲明這里要注意:ES6 引入了塊級作用域葛作,明確允許在塊級作用域之中聲明函數(shù)寿羞。但是考慮到環(huán)境導(dǎo)致的行為差異太大,應(yīng)該避免在塊級作用域內(nèi)聲明函數(shù)赂蠢。如果確實需要绪穆,也應(yīng)該寫成函數(shù)表達(dá)式,而不是函數(shù)聲明語句。
三玖院、const命令
- const聲明一個只讀的常量菠红。一旦聲明,常量的值就不能改變难菌。
- const聲明的變量不得改變值试溯,這意味著,const一旦聲明變量郊酒,就必須
立即
初始化遇绞,不能留到以后賦值
。- const的作用域與let命令相同:只在聲明所在的塊級作用域內(nèi)有效燎窘。
- const命令聲明的常量也是不提升摹闽,同樣存在暫時性死區(qū),只能在聲明的位置后面使用褐健。
本質(zhì)
const實際上保證的付鹿,
并不是變量的值不得改動
,而是變量指向的那個內(nèi)存地址
所保存的數(shù)據(jù)不得改動蚜迅。
對于簡單類型的數(shù)據(jù)
(數(shù)值舵匾、字符串、布爾值)谁不,值就保存在變量指向的那個內(nèi)存地址纽匙,因此等同于常量。但對于復(fù)合類型的數(shù)據(jù)
(主要是對象和數(shù)組)拍谐,變量指向的內(nèi)存地址,保存的只是一個指向?qū)嶋H數(shù)據(jù)的指針馏段,const只能保證這個指針是固定的(即總是指向另一個固定的地址)轩拨,至于它指向的數(shù)據(jù)結(jié)構(gòu)是不是可變的,就完全不能控制了院喜。因此亡蓉,將一個對象聲明為常量必須非常小心。
如果真的想將對象凍結(jié)喷舀,應(yīng)該使用
Object.freeze
方法砍濒。
ES6 聲明變量的六種方法
ES5 只有兩種聲明變量的方法:
var
命令和function
命令。ES6 除了添加let
和const
命令硫麻,還有另外兩種聲明變量的方法:import命令
和class
命令爸邢。所以,ES6 一共有 6 種聲明變量的方法拿愧。
四杠河、頂層對象的屬性
頂層對象,在
瀏覽器
環(huán)境指的是window對象
,在Node
指的是global
對象券敌。ES5 之中唾戚,頂層對象的屬性與全局變量是等價的
。
頂層對象的屬性與全局變量掛鉤待诅,被認(rèn)為是 JavaScript 語言最大的設(shè)計敗筆之一,原因如下:
- 沒法在編譯時就報出變量未聲明的錯誤叹坦,只有運行時才能知道(因為全局變量可能是頂層對象的屬性創(chuàng)造的,而屬性的創(chuàng)造是動態(tài)的)卑雁;
- 程序員很容易不知不覺地就創(chuàng)建了全局變量(比如打字出錯).
- 頂層對象的屬性是到處可以讀寫的募书,這非常不利于模塊化編程。
ES6 為了改變這一點序厉,一方面規(guī)定锐膜,為了保持兼容性,var命令和function命令聲明的全局變量弛房,依舊是頂層對象的屬性道盏;另一方面規(guī)定,
let命令文捶、const命令荷逞、class命令聲明的全局變量,不屬于頂層對象的屬性
粹排。也就是說种远,從 ES6 開始望艺,全局變量將逐步與頂層對象的屬性脫鉤莹桅。
五、global對象
ES5 的頂層對象砚蓬,本身也是一個問題射富,因為它在各種實現(xiàn)里面是不統(tǒng)一的膝迎。
- 瀏覽器里面,頂層對象是
window
胰耗,但 Node 和 Web Worker 沒有window限次。 - 瀏覽器和 Web Worker 里面,
self
也指向頂層對象柴灯,但是 Node 沒有self卖漫。 - Node 里面,頂層對象是
global
赠群,但其他環(huán)境都不支持羊始。
同一段代碼為了能夠在各種環(huán)境,都能取到頂層對象查描,現(xiàn)在一般是使用this變量店枣,但是有局限性速警。
很難找到一種方法,可以在所有情況下鸯两,都取到頂層對象闷旧。下面是兩種勉強可以使用的方法。
// 方法一
(typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this);
// 方法二
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};