普通類型和對(duì)象的區(qū)別

JavaScript的7種數(shù)據(jù)類型中,number、string、boolean、null、undefined、symbol為基本數(shù)據(jù)類型,而object為復(fù)雜類型(complex type)。在計(jì)算機(jī)中,簡(jiǎn)單類型數(shù)據(jù)存放在棧(Stack)中,復(fù)雜類型的數(shù)據(jù)則存放在堆(Heap)中而其Heap地址存放在Stack里。
五個(gè)面試題

  • 第一題
var a = 1
var b = a
b = 2
請(qǐng)問 a 顯示是幾?  

當(dāng)執(zhí)行到var b=a時(shí),內(nèi)存中可以表示為(因?yàn)閍、b是number型數(shù)據(jù),所以是基本數(shù)據(jù)類型,存在stack中):

此時(shí)執(zhí)行b=2直接將 2 的值放在 b 的stack中,如:



所以b的改變并沒有影響到a,a的結(jié)果還是1。

  • 第二題
var a = {name: 'a'}
var b = a
b = {name: 'b'}
請(qǐng)問現(xiàn)在 a.name 是多少?

從上圖可知對(duì)于復(fù)雜類型,在棧(Stack)上存儲(chǔ)的是一個(gè)地址,在堆(Heap)上存儲(chǔ)的是數(shù)據(jù)。按照地址有指向關(guān)系。運(yùn)行到var b = a時(shí),是將a中的addr1地址復(fù)制一份放到b的stack中。當(dāng)運(yùn)行b = {name: 'b'}時(shí)是在heap中重新開出一塊放置{name: 'b'}且地址為2,并且b的地址更改為addr2。這個(gè)時(shí)候b指向addr1的作廢,重新指向2。所以這個(gè)時(shí)候a還是原來(lái)的。即a.name的結(jié)果是a。

  • 第三題
var a = {name: 'a'}
var b = a
b.name = 'b'
請(qǐng)問現(xiàn)在 a.name 是多少?

當(dāng)運(yùn)行至var b = a時(shí)a和b的指向相同,此時(shí)運(yùn)行b.name = 'b',更改了heap中地址1中的信息,如圖所示。所以這個(gè)時(shí)候a.name的結(jié)果是{name: 'b'}。

  • 第四題
var a = {name: 'a'}
var b = a
b = null
請(qǐng)問現(xiàn)在 a 是什么?

當(dāng)運(yùn)行至var b = a時(shí)a和b的指向相同,這個(gè)時(shí)候運(yùn)行b = null(這是一個(gè)普通類型,直接將null的值在stack中給向b),所以導(dǎo)致b在heap中的指向消失并沒有改變heap內(nèi)存中數(shù)據(jù)。所以a的結(jié)果還是本身,即{name: 'a'}。

  • 第五題



    a.x=a={n:2}一句實(shí)際上寫成“a={n:2};a.x=a”更為直觀。第一句var a={n:1}操作在heap里存放“n:1”,stack里存放“a:ADDR78”指向heap這里;2句“var b=a”則在stack里放入“b:ADDR78”;3句把“a(a此時(shí)門牌號(hào)為78)={n:2}”賦給“a.x(a此時(shí)門牌號(hào)仍為78)”,根據(jù)=運(yùn)算符從右至左的規(guī)定先執(zhí)行“a={n:2}”——新造n:2放入79號(hào)房間并把門牌號(hào)79傳給a,則stack里a:ADDR79;再執(zhí)行“a.x(門牌號(hào)78)='ADDR79'”,即在78號(hào)倉(cāng)房里新放入了“x:ADDR79”;至此,alert(a.x)去找棧里a映射的79號(hào)房里并沒有x這么個(gè)名的東東,所以輸出“undefined”。而alert(b.x)時(shí),Stack里b一直映射Heap的78號(hào)地址,里面的x值為ADDR79,alert調(diào)用toString()方法將對(duì)象ADDR79輸出[object Object]。

小結(jié)

JS在數(shù)據(jù)區(qū)分為棧內(nèi)存(Stack)和堆內(nèi)存(Heap)。普通類型只是在棧內(nèi)存中運(yùn)行,而對(duì)象的是堆內(nèi)存中存儲(chǔ)數(shù)據(jù)在棧內(nèi)存中存儲(chǔ)heap地址,同過引用關(guān)系。
值類型之間傳遞的是值,引用類型之間傳遞的是地址(引用)。
值類型作為函數(shù)的參數(shù)傳遞的是值,引用類型作為函數(shù)的參數(shù)傳遞的是地址(引用)。

深拷貝和淺拷貝

var a = 1
var b = a
b = 2 

上邊的代碼中當(dāng)對(duì)b改變a完全不受影響,即為深拷貝。
對(duì)于簡(jiǎn)單類型中,賦值就是深拷貝。
對(duì)于復(fù)雜類型(對(duì)象),就有深拷貝和淺拷貝一說(shuō)。因?yàn)閺?fù)雜類型存在引用關(guān)系,所以在更改其中一個(gè)對(duì)象時(shí),兩者的指向還是相同的,即存在一個(gè)發(fā)生變化,另個(gè)也一起變化。

垃圾回收
垃圾回收是指,若一個(gè)對(duì)象沒有被引用,它便是垃圾將被瀏覽器回收。

參考資料一
參考資料二

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容