眾所周知,js中的var聲明存在變量提升機制,因此ESMAScript 6引用了塊級作用域來強化對變量生命周期的控制
let const 聲明不會被提升,有幾個需要注意的點
1、不能被重復聲明
假設作用域中已經存在某個標識符(無論該標識符是通過var聲明還是let、const變量聲明),此時再使用let或const關鍵定聲明會拋錯
var count=10 let count=20// 此處則會拋出錯誤,因為同一作用域內不能重復聲明
如果當前作用域內嵌另一個作用域,便可在內嵌的作用域中用let聲明同名變量
var count=10 if(true){ let count=20 }
2、const聲明的常量必須進行初始化
像下面這樣聲明就會報錯
const name;//語法錯誤,常量未初始化
3、不可以為const定義的常量再賦值,真正的本質是const聲明不允許修改綁定,但允許修改值(也就是說const聲明對象后,可以修改該對象的屬性值)
const person={ name:'angela' } //可以修改對象屬性的值 person.name='yun' // 修改綁定則會拋出語法錯誤 person={ 'name':'Shining' }
4、臨時性死區(Temporal Dead Zone)
JavaScript引擎在掃描代碼發現變量聲明時,要么將它們提升至作用域頂部(遇到var聲明),要么將聲明放到TDZ中(遇到let和const聲明),訪問TDZ中的變量會觸發運行時錯誤,只有執行過變量聲明語句后,變量才會從TDZ中移出,才能正常訪問
如下代碼就因為在if塊級作用域內執行console.log時value已經在TDZ中了,以前typeof是一個相對不易出錯的操作符,但其實也無法阻擋引擎拋出錯誤
在聲明前訪問塊級綁定會導致錯誤,因為綁定在臨時死區中
if (true) { console.log(typeof value)//引用錯誤 let value = 'blue' }
而在let聲明的作用域外對該變量使用typeof則不會報錯
console.log(typeof value) if (true) { let value = 'blue' }
5、塊級作用域綁定
之前在循環中創建函數都有些不可言狀
var funcs = [] for (var i = 0; i < 10; i++) { funcs.push(function () { console.log(i) }) } funcs.forEach(function (func) { func() })
因為循環內部創建的函數全部都保留了對相同變量的引用,循環結束時變量i的值為10,所以結果會輸出10次10
于是大家會在循環中使用立即調用函數表達式,以強制生成計數器變量的副本,以便輸出1、2、3......
var funcs = [] for (var i = 0; i < 10; i++) { funcs.push((function (value) { return function () { console.log(value) } })(i)) } funcs.forEach(function (func) { func() })
有了let,立即調用函數表達式則可以簡化,其實每次迭代循環都會創建一個新變量,并以之前迭代中同名變量的值將其初始化
var funcs = [] for (let i = 0; i < 10; i++) { //其實是每次循環的時候let聲明都會創建一個新變量i并將其初始化為i的當前值,所以在循環內部創建的每個函數都能得到屬于它們自己的i的副本 funcs.push(function () { console.log(i) }) } funcs.forEach(function (func) { func()//這里
這個特性同樣適用于for in中,舉例來說
var funcs = [], obj = { a: true, b: true, c: true } for (let key in obj) { funcs.push(function () { console.log(key) }) } funcs.forEach(function (func) { func()//
6、循環中的let聲明特性同樣適用于const聲明,唯一的區別是const不能更改綁定
上面的例子中把let換成const同樣輸出a b c
var funcs = [], obj = { a: true, b: true, c: true } //之所以可以運用for in 和for of循環中,是因為每次迭代不會修改已有綁定,而是會創建一個新綁定 for (const key in obj) { funcs.push(function () { console.log(key)// 同樣
下面的這個例子則會報錯,因為在for循環中更改了i的綁定而const常量不能更改綁定
var funcs = [] for (const i = 0; i < 10; i++) { funcs.push(function () { console.log(i) }) } funcs.forEach(function (func) { func() })
7、全局作用域綁定
當var被作用于全局作用域時,它會創建一個新的全局變量作用全局對象(瀏覽器環境中的window對象)的屬性,這意味著用var很可能會無意中覆蓋一個已經存在的全局變量
從上圖代碼中看出即便是全局對象RegExp Array都會被覆蓋
但是let或const會在全局作用域下創建一個新的綁定,但該綁定不會添加為全局對象的屬性,換句話說用let或const不能覆蓋全局變量,而只能遮蔽它
這個時候的RegExp和window.RegExp是不相同的
let RegExp='hello' console.log(RegExp) //hello console.log(window.RegExp===RegExp)//false const ncz='hi' console.log(ncz) console.log("ncz" in window)
最佳實踐:
默認使用let而不是var
默認使用const,只有確實需要改變變量的值時使用let
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com