js 引擎如何在瀏覽器儲存普通類型和對象
JavaScript 的數據類型分為7種:string, number, boolean, null, undefined, symbol, object。
其中 string, number, boolean 合稱為原始類型 (primitive type) 的值;null, undefined 一般則稱為特殊值。至於 object 則稱為合成類型(complex type) 的值,object 是複雜的數據類型,又可分為3個子類型:object, array, function。
這篇文章會針對 object 這個類型,帶出瀏覽器如何處理它。
一般來說,要了解這個過程,你要了解:內存(Ram)與瀏覽器。當你使用瀏覽器時,會佔用了電腦的內存,瀏覽器會將內存再分配給 HTML & CSS 渲染,HTTP 處理,瀏覽器外殼,JS 引擎等等。而 object 的處理就是在 JS 引擎內發生。
棧內存 (Stack) 和堆內存 (Heap)
JS 引擎將得到的內存,並分為代碼區及數據區。而普通類型和對象的區別主要體現在數據區。數據區內則分為棧內存 (Stack) 和堆內存 (Heap)。簡單類型的數據會直接存在 Stack 裡。複雜類型的數據是把 Heap 地址存在 Stack 裡。以下是整個瀏覽器處理數據類型的結構:
以下會通過內存圖概念去解釋數據類型如何存放在 stack 及 heap 之間。
例題一:
var a = 1
var b = a
b = 2
a//等於什麼?
當 var a = 1
,var b = a
,內存可以表示為:
當執行b=2
直接將2
的值放在b
的stack中,如:
所以b
的改變並沒有影響到a
, a=1
例題二:
var a = {name: ‘a’}
var b = a
b = null
a.name//等於什麼?
當執行var a = {name: ‘a’}
,var b = a
時, a
和b
指向相同的ADDR 1
(圖2a)。這個時候執行b = null
(這是一個普通類型,直接將null
的值在stack
中給b
),導致b
在heap
中的指向消失(圖2b),不會改變heap
內存中數據。所以a
還是{name: 'a'}
。
例題三:
var a = {name: ‘a’}
var b = a
b.name = ‘b’
a.name//等於什麼?
當執行var a = {name: ‘a’}
,var b = a
時, a
和b
指向相同的ADDR 1
。這個時候執行b.name = 'b'
,更改在heap
中地址ADDR 1
,所以a.name
是{name: 'b'}
。
例題四:
var a = {name: ‘a’}
var b = a
b = {name:’b’}
a.name//等於什麼?
當執行var a = {name: ‘a’}
,var b = a
時, a
和b
指向相同的ADDR 1
。這個時候執行b = {name:’b’}
(由於這是定義了新的對象),導致b
在heap
中原先指向ADDR 1
消失,在heap
中新增了ADDR 2
,把b
指向了ADDR 2
,而a
沒有變化,所以a.name
是a
。
深拷貝和淺拷貝
var a = 1
var b = a
b = 2
上邊的代碼中當對b改變一個完全不受影響,即為深拷貝。對於簡單類型中,賦值就是深拷貝。對於複雜類型(對象),就有深拷貝和淺拷貝一說。因為複雜類型存在引用關係,所以在更改其中一個對象時,兩者的指向還是相同的,即存在一個發生變化,另個也一起變化。
GC垃圾回收機制
如果一個對象沒有被引用就是垃圾,將被回收。
例子:
var fn = function(){};
document.body.onclick=fn
fn = null
//fn = function(){}; 會否被回收?
答案是不會,雖然這個時候執行fn = null
(這是一個普通類型,直接將null
的值在stack
中給向fn
),fn
被賦值null
,function(){}
的指向消失。但因為document.body.onclick
仍引用function(){}
,所以沒有被回收。
以上就是有關stack
,heap
,深拷貝和淺拷貝,GC垃圾回收機制的內容。