JS不同型別變數的記憶體分配

2020-07-16 10:05:28
JavaScript 的所有變數(包括函數)在整個處理過程中都是存放在記憶體中的,所以要對一個變數進行處理。首先得為變數分配記憶體。JavaScript 記憶體分配和其他許多語言一樣,是根據變數的資料型別來分配記憶體的,而 JavaScript 變數的資料型別由所賦的值的型別決定。

JavaScript 支援的資料型別可分為兩大類:基本資料型別和複雜資料型別。其中基本資料型別包含了數位(number)型別、字串(string)型別、布林(boolean)型別、未定義(undefined)型別、空(null)型別;複雜資料型別包含了物件(object)型別,在 JavaScript 中陣列、函數都屬於物件型別。除了基本資料型別以外的資料型別全都是物件型別。

在 JavaScript 中,基本資料型別變數分配在棧記憶體中,其中存放了變數的值,對其是按值來存取的;而物件型別的變數則同時會分配棧記憶體和堆記憶體,其中棧記憶體存放的是地址。堆記憶體存放的是參照型別的值,棧記憶體存放的地址指向堆記憶體中存放的值。對該變數的存取是按參照來存取的,即首先讀取到棧記憶體存放的地址,然後按該地址找到堆記憶體讀取其中存放的值。

JavaScript 之所以按變數的不同資料型別來分配記憶體,主要原因是棧記憶體比堆記憶體小,而且棧記憶體的大小是固定的,而堆記憶體大小可以動態變化。基本資料型別的值的大小固定,物件型別的值大小不固定,所以將它們分別存放在棧記憶體和堆記憶體是合理的。

接下來以下面的程式碼為例,以圖示的方法介紹其中不同型別變數的記憶體分配情況。
function Student(id,sno,name,age){ //函數定義,Student是一個函數變數
     this.id = id;
     this.sno = sno;
     this.name = name;
     this.age = age;
}
var num = 20; //num是一個數位變數
var bol = false; //bol是一個布林變數
var str = "student"; //str是一個字串變數
var obj ={}; //obj是一個物件變數
var arr = ['a','b','c']; //arr是一個陣列變數
var student = new Student(1,"2017010200016","小華",18);//student是一個物件變數

上述程式碼中的 Student 變數定義了一個建構函式(有關建構函式以及後面的使用建構函式和使用{}建立物件的內容之後介紹),函數的定義程式碼存放在堆記憶體中,該記憶體對應的地址存放在 Student 函數變數中。建構函式用於建立物件範例,最後一行程式碼正是使用了該建構函式來建立了一個名字為小華的學生物件範例。學生範例建立完後會返回其在堆記憶體中分配的地址,該地址被賦給了 student 變數。

上述程式碼中的{}在堆記憶體中建立了一個空物件,該物件的堆記憶體中的地址被賦給了 obj 變數。['a','b','c'] 是一個元素值分別為 'a'、'b'、'c' 的陣列物件,該物件也在堆記憶體中存放,其對應的地址賦給了 arr 變數。除了 Student、obj、arr 和 student 這幾個變數為物件變數外,其他幾個變數 num、bol、str 都是基本資料型別的變數,因而它們都儲存在棧記憶體中。

上述程式碼中各個型別變數的記憶體分配情況如圖 1 所示。
不同類型變量的內存分配情況
圖 1:不同型別變數的記憶體分配情況