在看JS內存機制之前我們先來看一下JS是門什麼樣的語言,他又有哪些變量類型。
動靜態,強弱類型
靜態:在使用之前就需要確認其變量數據類型。
動態:在運行過程中需要檢查數據類型。
強類型:不支持隱式類型轉換。
弱類型:支持隱式類型轉換。
而JS呢,則是一種動態弱類型的語言。
JS的變量類型
JS的變量類型分爲8種,注意⚠️:其中Symbol爲ES6新增,BigInt爲ES11新增
類型 |
描述 |
Number |
基於IEE754標準的雙精度64位二進制格式的值,範圍爲2的63次方減一到負的2的63次方減一 |
String |
用於表示文本數據,⚠️JS裏面字符串是不可變的 |
Boolean |
布爾值,只有true和false |
Undefined |
一個沒有被賦值的變量值爲undefined,變量提升的默認值也是undefined |
Null |
空的初始值,只有一個值Null |
Symbol |
符號類型,唯一且不可修改 |
BigInt |
可以用任意精度表示數字,即使超出Number的安全範圍也可以正常操作 |
Object |
對象,可以看作一組屬性的集合 |
注意:⚠️
- typeOf Null 爲Object,原因在於在JS最初版本000開頭的爲對象,而Null全爲0,故導致爲Object。
- 前七種稱爲基本數據類型(原始數據類型),最後一種爲複雜數據類型又稱爲引用數據類型(合成數據類型)。
JS的內存
js的內存空間分爲棧(stack)、堆(heap)、池(一般也會歸類棧中)。其中棧存放變量,堆存放複雜對象,池存放常量,所以也叫常量池。
棧
棧空間就是我們之前反覆提及的調用棧,是用來存儲執行上下文的。基本數據類型的變量值都被保存在執行上下文中,而執行上下文又被壓入到棧中,所以你也可以認爲基本數據類型都是存放在棧中的(除了閉包)
堆
複雜數據類型的變量都是存儲在堆中的,而複雜數據類型的引用則是存儲在棧中的。當訪問複雜數據類型的時候相當於多了一道轉手的流程。
對比
區別 |
棧 |
堆 |
數據結構 |
棧結構 |
堆結構 |
存儲內容 |
基本數據類型和複雜數據類型的引用 |
複雜數據類型和閉包 |
空間 |
空間比較小 |
空間很大 |
經過以上我們可以得出除閉包外,基本數據類型的變量都是存儲在棧中,而複雜數據類型都是存儲在堆中,而複雜數據類型的引用則存儲在棧中。
注意⚠️:原始類型的賦值會完整複製變量值,而引用類型的賦值是複製引用地址。
問題
爲什麼一定要分堆和棧兩個存儲空間呢?
原因在於 JavaScript 引擎需要用棧來維護程序執行期間上下文的狀態,如果棧空間大了話,所有的數據都存放在棧空間裏面,那麼會影響到上下文切換的效率,進而又影響到整個程序的執行效率
JS變量有哪幾類?
JS裏面堆存儲和棧存儲有什麼區別?
Null和Undefined的區別?
原因:
其實最初JS也是隻有null,但後來JS的設計者覺得這樣不太好,原因有如下兩點
- null像在Java裏一樣,被當成一個對象。但是,JavaScript的數據類型分成原始類型(primitive)和合成類型(complex)兩大類,Brendan Eich覺得表示"無"的值最好不是對象。
- JS的最初版本沒有包括錯誤處理機制,發生數據類型不匹配時,往往是自動轉換類型或者默默地失敗。Brendan Eich覺得,如果null自動轉爲0,很不容易發現錯誤。
區別:
null是一個表示"無"的對象,轉爲數值時爲0;undefined是一個表示"無"的原始值,轉爲數值時爲NaN。
null代表沒有對象,即此處不應該有值,用法:
- 作爲函數的參數,表示該函數的參數不是對象。
- 作爲對象原型鏈的終點。
undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義,使用:
一變量二函數一對象
- 變量被聲明瞭,但沒有賦值時,就等於undefined。
- 調用函數時,應該提供的參數沒有提供,該參數等於undefined。
- 函數沒有返回值時,默認返回undefined。
- 對象沒有賦值的屬性,該屬性的值爲undefined。
參考
阮一峯Null和undefined區別
瀏覽器工作原理與實戰