本章涉及3個知識點,var、let、const,如今讓咱們瞭解3個關鍵字的特性和使用方法。react
JavaScript中,咱們一般說的做用域是函數做用域,使用var聲明的變量,不管是在代碼的哪一個地方聲明的,都會提高到當前做用域的最頂部,這種行爲叫作變量提高(Hoisting)面試
也就是說,若是在函數內部聲明的變量,都會被提高到該函數開頭,而在全局聲明的變量,就會提高到全局做用域的頂部。segmentfault
function test() { console.log('1: ', a) //undefined if (false) { var a = 1 } console.log('3: ', a) //undefined } test()
實際執行時,上面的代碼中的變量a會提高到函數頂部聲明,即便if語句的條件是false,也同樣不影響a變量提高。閉包
function test() { var a //a聲明沒有賦值 console.log('1: ', a) //undefined if (false) { a = 1 } //a聲明沒有賦值 console.log('3: ', a) //undefined }
在函數嵌套函數的場景下,變量只會提高到最近的一個函數頂部,而不會。異步
//b提高到函數a頂部,但不會提高到函數test。 function test() { function a() { if (false) { var b = 2 } } console.log('b: ', b) } test() //b is not defined
若是a沒有聲明,那麼就會報錯,沒有聲明和聲明後沒有賦值是不同的,這點必定要區分開,有助於咱們找bug。函數
//a沒有聲明的狀況 a is not defined
let和const都可以聲明塊級做用域,用法和var是相似的,let的特色是不會變量提高,而是被鎖在當前塊中。code
一個很是簡單的例子:對象
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
惟一正確的使用方法:先聲明,再訪問。ip
function test() { if(true) { let a = 1 console.log(a) } } test() // 1
聲明常量,一旦聲明,不可更改,並且常量必須初始化賦值。作用域
const type = "ACTION"
咱們試試從新聲明type,看看會報什麼錯:
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和let都是在當前塊內有效,執行到塊外會被銷燬,也不存在變量提高(TDZ),不能重複聲明。
不一樣點:const不能再賦值,let聲明的變量能夠重複賦值。
上面咱們也提到了TDZ的場景,那麼,有什麼用呢?答案就是沒什麼用。
臨時死區的意思是在當前做用域的塊內,在聲明變量前的區域叫作臨時死區。
if (true) { //這塊區域是TDZ 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沒法污染外部函數
關於這個使用場景的具體分析能夠查看我寫的另一篇文章:JavaScript同步、異步、回調執行順序之經典閉包setTimeout面試題分析
若是在全局做用域使用let或者const聲明,當聲明的變量自己就是全局屬性,好比closed。只會覆蓋該全局變量,而不會替換它。
window.closed = false let closed = true closed // true window.closed // false
在實際開發中,咱們選擇使用var、let仍是const,取決於咱們的變量是否是須要更新,一般咱們但願變量保證不被惡意修改,而使用大量的const,在react中,props傳遞的對象是不可更改的,因此使用const聲明,聲明一個對象的時候,也推薦使用const,當你須要修改聲明的變量值時,使用let,var能用的場景均可以使用let替代。