js是弱類型語言,語法很鬆散,這是一個缺點。es6
以前,在js中變量聲明:var。瀏覽器
爲了解決這個缺點,js中聲明變量新增兩個語法:let、constbabel
特色有三:閉包
let/const聲明的變量不會進行變量聲明提高:異步
let/const重複聲明一個變量報錯。 若是這個變量已經被var過了,也不能再繼續let/const定義了: 函數
延伸到函數的行參上:工具
函數行參在函數內部也是至關於var了一個變量的存在。性能
用var定義變量覆蓋行參:spa
可是若是在函數內部用let聲明一個和行參同名的變量,就會報錯:3d
let/const聲明的變量不會掛在到window上,var會(容易形成混亂和衝突,window上的原有屬性不能隨便改)。
let/const增強對做用域的控制:
做用域就是變量的生命週期,或者說變量在哪裏可以被使用。
也就說let/const能讓變量的生命週期更精準、更規範。(具體如何控制?)
當let/const配合{}使用時能產生塊級做用域。
換句話說,只要有大括號,在大括號中let/const一個變量,該變量的生命週期就是這個大括號。
對比var 的效果
塊級做用域嵌套:
外部父塊級做用域定義的變量,內部子塊級裏能獲取到。
也就是說雖然產生塊級做用域,可是在裏邊仍是能看到外邊的,在塊級裏能看到全局,在子塊級裏能看到父塊級。這就是塊級做用域。
下圖,在子塊裏console父塊的變量hah,依然能夠拿到。
臨時死區【Temporal Dead Zone】
只要一個變量在一個做用域內用let/const聲明瞭,那這個變量聲明就在整個做用域裏邊稱霸了,也就是說在這個做用域中就是惟一不可重複聲明的了。
同時,若是let/const聲明瞭一個變量,當咱們在這個變量所處的做用域中、在變量聲明以前就「預支」引用的話,就會報錯。
由於:在做用域(全局/函數/塊級)內、某變量的let/const聲明以前,就是這個變量的臨時死區,黑暗地帶。摸不到、也看不到這個變量,使用的話就會觸發報錯警告。
上圖,報錯位置就是由於我在臨時死區內引用了let聲明的變量致使的。
以上,若是子塊裏邊沒有let/const聲明一個和父級同名的變量,那將相安無事。子塊級的變量使用仍是會去父塊級或全局中去找。
若是給子塊級「膽子」,聲明瞭和父級中已有的同名變量,那他就敢「造反」,整個子塊中的這個同名變量他說了算。此時若是在子塊範圍內、let/const聲明以前使用這個變量,就會報錯。
let/const聲明其餘和父塊級或全局變量不重名的變量倒沒有關係。
關於這個知識點,借用一下阮一峯老師的文檔說明,一圖勝千言:
【const特殊】const定義的常量不能修改,let和var能夠。
他其實跟var仍是挺像的,只不過var的是局部函數做用域、let和const是局部塊級做用域;var的變量聲明提高,let和const的變量聲明不提高且報錯而已。
{ let test = 1; console.log(test); { console.log(test); let test = 2; { let test = 3; } } }
CONST:常量聲明。定義一個常量。這個常量不能被改變。
有如下特色須要注意
const聲明變量時,必須當即賦值:
因此,須要先實現聲明一個空變量,且後期會動態改變此變量的狀況,就得考慮用let聲明。
const定義的常量,不能再作修改:
const定義的常量,在棧內存的地址不能修改。
可是const定義的引用類型值的常量,其屬性值或項仍是能改:
不過,略微修改結果又變得和原始值同樣:
修改const常量的指針會報錯。可是修改堆空間的屬性值卻沒有關係。
存儲常量的空間裏邊的值不能發生改變。存儲常量的空間在棧空間,也就是棧裏邊存放的值不能改變。不表明堆內存裏邊的值不能改變。
const定義的常量讓瀏覽器很省心、讓開發人員也很省心:
const的效率可能比var和let就高一點,由於不少業界大牛猜想,瀏覽器中會對const變量少了一些追蹤,
不像let和var要時刻去檢測它有沒有變化。一旦監控就須要一些算力。可是const聲明後就不用去檢測了,
因此不管從提高效率仍是下降bug出現機率上看,都應該先使用const。
const結語:
能用const就用const。雖然babel轉換後他仍是var。
在聲明後從新賦值這方面觀察:
能夠看到,let和const都被轉換成了var。可是他們的特色仍是被曲線救國的招式給保留了:
let聲明的變量,在此修改,沒有問題。轉換成var之後做用一致。
可是const就不同了,const聲明的是常量,轉成var後不會有這個功能,可是babel建立了一個_readOnlyError的內部報錯對象,監測到const常量被從新賦值後就調用該函數向控制檯拋出了一個錯誤以提示開發者。
在變量聲明提高的方面觀察:
遺憾的是,let轉換後變成var,有了變量提高,轉換前(左邊)直接運行是確定會報錯的,轉換後打印undefined,說明變量提高生效了。babel沒有對這一點進行處理。
塊級做用域方面觀察:
在塊級裏邊的引用也被處理了(console部分)。
這一次babel確實處理了,是將大括號裏邊用let聲明的變量名加了個下劃線,以和塊級外邊作了區分,同樣達到了在外邊變量會報錯的結果。
但一樣遺憾的是,對於全局做用域內聲明的變量會掛在到window上這一點,依舊沒有作防護工做。
babel編譯後的變量仍是會掛在到window對象上。
最後對於經典題的觀察:
可見,利用let解決的異步回調裏引用循環後的全局變量問題,一樣也是閉包的原理實現的。
2019-05-02 20:10:52