在JS中,有六種數(shù)據(jù)類(lèi)型,分別是數(shù)值(Number)、字符串(String)、布爾型(Boolean)、undefined、null以及對(duì)象(object),其中又分為基本類(lèi)型和引用類(lèi)型、
一、基本類(lèi)型和引用類(lèi)型
- 基本類(lèi)型
1.基本類(lèi)型指的是什么?
JS中的基本類(lèi)型指的是存儲(chǔ)在棧內(nèi)存中的數(shù)據(jù)片段;
他們存儲(chǔ)在棧內(nèi)存中;
2.基本類(lèi)型有哪些?
基本類(lèi)型包括:數(shù)值、字符串、布爾型、undefined和null;
(PS:在其它的語(yǔ)言中,字符串可能是引用類(lèi)型,但是JS中的字符串是基本類(lèi)型) - 引用類(lèi)型
1.引用類(lèi)型指的是什么?
JS中的引用類(lèi)型指的就是對(duì)象,以及屬于對(duì)象的函數(shù)、數(shù)組等;
他們存儲(chǔ)在堆內(nèi)存中;
2.引用類(lèi)型有什么?
引用類(lèi)型包括:對(duì)象、正則表達(dá)式、函數(shù)、數(shù)組等; - 關(guān)于基本類(lèi)型和引用類(lèi)型的值的存儲(chǔ)
如果將數(shù)據(jù)賦值給一個(gè)變量,那么就相當(dāng)于在內(nèi)存中開(kāi)辟了一個(gè)空間,該空間存儲(chǔ)這個(gè)數(shù)據(jù),然后這個(gè)空間的名字就是變量名;
那么,基本類(lèi)型的賦值和引用類(lèi)型的賦值有什么不同呢?
用以下例子進(jìn)行說(shuō)明:- 首先有兩個(gè)變量a和b,分別將1和對(duì)象
{z: 1}
賦值給他們,相當(dāng)于在內(nèi)存中開(kāi)辟了兩個(gè)空間a和b,他們分別存儲(chǔ)了1和{z: 1}
的數(shù)據(jù),a空間存儲(chǔ)的是數(shù)值1,那么b空間存儲(chǔ)的是什么呢?:
- 答案:因?yàn)?code>{z: 1}是一個(gè)對(duì)象,他是存儲(chǔ)在堆內(nèi)存中的一個(gè)數(shù)據(jù),而b存儲(chǔ)的是指向這個(gè)數(shù)據(jù)存放地址的一個(gè)指針,我假設(shè)這個(gè)指針為
0x0011
,所以b的值其實(shí)就是0x0011
,并不是這個(gè)對(duì)象:
以上就是基礎(chǔ)類(lèi)型變量和引用類(lèi)型變量的不同點(diǎn);
- 首先有兩個(gè)變量a和b,分別將1和對(duì)象
二、關(guān)于函數(shù)的參數(shù)傳遞
- 介紹
一個(gè)函數(shù)如果有形參,那么在進(jìn)行實(shí)參傳遞的時(shí)候,相當(dāng)于在該函數(shù)內(nèi)部聲明了一個(gè)變量,變量名是形參,我稱(chēng)之為形參變量,然后將實(shí)參的值賦值給該形參變量,后續(xù)的操作實(shí)際上是對(duì)形參變量進(jìn)行的操作,函數(shù)操作完畢后,形參變量被銷(xiāo)毀;
那么在函數(shù)參數(shù)的傳遞中,基本類(lèi)型和引用類(lèi)型又有什么不同呢? -
基本類(lèi)型的參數(shù)傳遞
有如下例子,輸出結(jié)果如下:
基本類(lèi)型的函數(shù)參數(shù)傳遞
那么為什么執(zhí)行fn(b)時(shí)打印的結(jié)果為3,而b的值卻未變化呢?
因?yàn)樵趫?zhí)行fn(b)的時(shí)候,函數(shù)體內(nèi)做了如下操作,所以自增操作實(shí)際上是對(duì)a的自增,不是對(duì)b的自增:
又因?yàn)閎的值是數(shù)值2,他是引用類(lèi)型,所以是將2這個(gè)數(shù)值賦值給了a,對(duì)a的操作并不影響b的值,并且操作完成后a被銷(xiāo)毀,b不變;
- 引用類(lèi)型的參數(shù)傳遞
有如下例子,輸出結(jié)果如下:
引用類(lèi)型的函數(shù)參數(shù)傳遞
那么為什么執(zhí)行fn(b)后,b又發(fā)生了改變了呢?
原理同上,但是因?yàn)?code>{age: 33}是個(gè)對(duì)象,是引用類(lèi)型,所以b存儲(chǔ)的實(shí)際上是一個(gè)指向該對(duì)象的指針,然后在執(zhí)行fn(b)的時(shí)候var a = b
,實(shí)際上是將b存儲(chǔ)的指針賦值給了a,a和b指向同一對(duì)象:
然后通過(guò)a這個(gè)指針對(duì)對(duì)象{age: 33}進(jìn)行了自增操作,對(duì)象就變了,而b也指向這個(gè)對(duì)象,所以通過(guò)b查看該對(duì)象也能發(fā)現(xiàn)該對(duì)象已經(jīng)變了,所以結(jié)果如下;
三、對(duì)象的拷貝
針對(duì)對(duì)象的拷貝有深拷貝和淺拷貝兩種
- 淺拷貝
-
應(yīng)用場(chǎng)景:
當(dāng)對(duì)象只有一層,也就是對(duì)象的屬性所對(duì)應(yīng)的值只有基本類(lèi)型的時(shí)候,可以使用淺拷貝,方法如下:
原理:先創(chuàng)建一個(gè)新對(duì)象newObj,這一步讓新對(duì)象的指針與老對(duì)象的指針不一樣,兩者就被區(qū)分開(kāi)來(lái),然后使用for...in...循環(huán)遍歷老對(duì)象,將老對(duì)象的鍵值對(duì)傳入到新對(duì)象中,在返回這個(gè)新對(duì)象;
- 但是當(dāng)對(duì)象中含有對(duì)象,也就是該對(duì)象有兩層或多層時(shí)用淺拷貝就會(huì)發(fā)生如下問(wèn)題:
對(duì)老對(duì)象的修改影響到了新對(duì)象,原因是因?yàn)樵谶@個(gè)例子中:老對(duì)象的z是指向{age: 33}
這個(gè)對(duì)象的指針,只進(jìn)行淺拷貝的話,新對(duì)象的z拷貝過(guò)來(lái)的值也是指向{age: 33}
的指針,新老對(duì)象共用一個(gè){age: 33}
,所以無(wú)論通過(guò)新老z指針對(duì)其進(jìn)行修改,都會(huì)對(duì)兩者產(chǎn)生影響:
像這種情況我們就要使用深拷貝的方法了。
-
- 深拷貝的兩種方法
-
使用遞歸
原理:針對(duì)對(duì)象中的值進(jìn)行判斷,若該值指向的還是對(duì)象,就將這個(gè)值作為參數(shù)傳遞進(jìn)原函數(shù)進(jìn)行再次判斷進(jìn)而拷貝,若值是基本類(lèi)型則采用淺拷貝的方法進(jìn)行拷貝。
(PS:null雖然類(lèi)型是對(duì)象,但是卻屬于基本類(lèi)型)
遞歸方法進(jìn)行深拷貝
輸出結(jié)果:
-
使用JSON對(duì)象的stringify和parse方法
原理:
1.用JSON對(duì)象的stringify方法將對(duì)象轉(zhuǎn)化為字符串,此時(shí)該對(duì)象失去了對(duì)象的特性,成了基本類(lèi)型;
2.再使用JSON對(duì)象的parse方法將其轉(zhuǎn)化為變回一個(gè)對(duì)象;
3.比喻:將一棟房子拆除,即使用原來(lái)的材料重建一棟和原來(lái)一模一樣的房子,新房子和老房子也不會(huì)是同一棟房子;
代碼如下:
使用JSON對(duì)象的方法進(jìn)行深拷貝
輸出結(jié)果:
-