主要知識點有:var變量提高、let聲明、const聲明、let和const的比較、塊級綁定的應用場景
![]()
JavaScript中,咱們一般說的做用域是函數做用域,使用var聲明的變量,不管是在代碼的哪一個地方聲明的,都會提高到當前做用域的最頂部,這種行爲叫作變量提高(Hoisting)segmentfault
function test() { var a //a聲明沒有賦值 console.log('1: ', a) //undefined if (false) { a = 1 } //a聲明沒有賦值 console.log('3: ', a) //undefined }
test()閉包
若是a沒有聲明,那麼就會報錯,沒有聲明和聲明後沒有賦值是不同的,這點必定要區分開,有助於咱們找bug。函數
//b提高到函數a頂部,但不會提高到函數test。 function test() { function a() { if (false) { var b = 2 } } console.log('b: ', b) } test() //b is not defined
let和const都可以聲明塊級做用域,用法和var是相似的,let的特色是不會變量提高,而是被鎖在當前塊中。spa
function test() { if(true) { console.log(a)//TDZ,俗稱臨時死區,用來描述變量不提高的現象 let a = 1 } } test() // a is not defined function test() { if(true) { let a = 1 } console.log(a) } test() // a is not defined
惟一正確的使用方法:先聲明,再訪問。code
function test() { if(true) { let a = 1 console.log(a) } } test() // 1
聲明常量,一旦聲明,不可更改,並且常量必須初始化賦值。對象
const type = "ACTION"
從新賦值會報錯blog
const type = "ACTION" type = 1 console.log(type) //"type" is read-only const type = "ACTION" let type = 1 console.log(type) //Duplicate declaration "type"
const雖然是常量,不容許修改默認賦值,但若是定義的是對象Object,那麼能夠修改對象內部的屬性值。圖片
const type = { a: 1 } type.a = 2 //沒有直接修改type的值,而是修改type.a的屬性值,這是容許的。 console.log(type) // {a: 2}
const聲明不容許修改綁定,但容許修改綁定的值ip
const和let的異同點:
相同點:const和let都是在當前塊內有效,執行到塊外會被銷燬,也不存在變量提高(TDZ),不能重複聲明。
不一樣點:const不能再賦值,let聲明的變量能夠重複賦值。
臨時死區的意思是在當前做用域的塊內,在聲明變量前的區域叫作臨時死區。
if (true) { //這塊區域是TDZ,訪問a會報錯 let a = 1 }
訪問TDZ中的變量會觸發運行時錯誤
但下面這種不會報錯
console.log(typeof a) //undefined,由於此時a不在TDZ中 if (true) { //這塊區域是TDZ,訪問a會報錯 let a = 1 }
除了上面提到的經常使用聲明方式,咱們還能夠在循環中使用,最出名的一道面試題:循環中定時器閉包的考題
在for循環中使用var聲明的循環變量,會跳出循環體污染當前的函數。
for(var i = 0; i < 5; i++) { setTimeout(() => { console.log(i) //5, 5, 5, 5, 5 }, 0) } console.log(i) //5 i跳出循環體污染外部函數 //將var改爲let以後 for(let i = 0; i < 5; i++) { setTimeout(() => { console.log(i) // 0,1,2,3,4 }, 0) } console.log(i)//i is not defined i沒法污染外部函數
循環內const聲明
在普通的for循環中使用const變量,因爲const變量不可修改,所以會報錯。而在for-in或者for-of循環中可使用const變量。
由於循環爲每次迭代建立了一個新的變量綁定,而不是試圖去修改已綁定的變量的值
let arr = [1,2,3,4]; for(const item of arr){ console.log(item); //輸出1,2,3,4 }
用var做用域全局做用域時聲明的全局變量會覆蓋一個已經存在的全局屬性:
var reg = "hello"; console.log(window.reg) //"hello"
而若是在全局做用域使用let或者const聲明,當聲明的變量自己就是全局屬性,好比closed。會建立一個新的綁定,但不會添加全局屬性;就是說,用let或const不能覆蓋全局變量,只能遮蔽它;
window.closed = false let closed = true closed // true window.closed // false
在實際開發中,咱們選擇使用var、let仍是const,取決於咱們的變量是否是須要更新,一般咱們但願變量保證不被惡意修改,而使用大量的const,聲明一個對象的時候,也推薦使用const,當你須要修改聲明的變量值時,使用let,var能用的場景均可以使用let替代。