JS記憶體機制
在看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區別
瀏覽器工作原理與實戰