衆所周知,js中的var聲明存在變量提高機制,所以ESMAScript 6引用了塊級做用域來強化對變量生命週期的控制
let const 聲明不會被提高,有幾個須要注意的點
一、不能被重複聲明瀏覽器
假設做用域中已經存在某個標識符(不管該標識符是經過var聲明仍是let、const變量聲明),此時再使用let或const關鍵定聲明會拋錯
var count=10 let count=20// 此處則會拋出錯誤,由於同一做用域內不能重複聲明
若是當前做用域內嵌另外一個做用域,即可在內嵌的做用域中用let聲明同名變量函數
var count=10 if(true){ let count=20 }
二、const聲明的常量必須進行初始化
像下面這樣聲明就會報錯spa
const name;//語法錯誤,常量未初始化
三、不能夠爲const定義的常量再賦值,真正的本質是const聲明不容許修改綁定,但容許修改值(也就是說const聲明對象後,能夠修改該對象的屬性值)code
const person={ name:'angela' } //能夠修改對象屬性的值 person.name='yun' // 修改綁定則會拋出語法錯誤 person={ 'name':'Shining' }
四、臨時性死區(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' }
五、塊級做用域綁定
以前在循環中建立函數都有些不可言狀圖片
var funcs = [] for (var i = 0; i < 10; i++) { funcs.push(function () { console.log(i) }) } funcs.forEach(function (func) { func() })
由於循環內部建立的函數所有都保留了對相同變量的引用,循環結束時變量i的值爲10,因此結果會輸出10次10
因而你們會在循環中使用當即調用函數表達式,以強制生成計數器變量的副本,以便輸出一、二、3......ip
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()//這裏輸出是0 而後是一、2....9 })
這個特性一樣適用於for in中,舉例來講it
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()//輸出的是a b c })
六、循環中的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)// 一樣輸出a b c 惟一的區別是循環內不能更改key的值 }) } funcs.forEach(function (func) { func() })
下面的這個例子則會報錯,由於在for循環中更改了i的綁定而const常量不能更改綁定
var funcs = [] for (const i = 0; i < 10; i++) { funcs.push(function () { console.log(i) }) } funcs.forEach(function (func) { func() })
七、全局做用域綁定
當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