1. 程式人生 > 實用技巧 >JS記憶體機制

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代表沒有物件,即此處不應該有值,用法:

  1. 作為函式的引數,表示該函式的引數不是物件。
  2. 作為物件原型鏈的終點。

undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義,使用:

一變數二函式一物件

  1. 變數被宣告瞭,但沒有賦值時,就等於undefined。
  2. 呼叫函式時,應該提供的引數沒有提供,該引數等於undefined。
  3. 函式沒有返回值時,預設返回undefined。
  4. 物件沒有賦值的屬性,該屬性的值為undefined。

參考

阮一峰Null和undefined區別

瀏覽器工作原理與實戰