聊一聊web前端那些事兒,關於深拷貝和淺拷貝


深拷貝和淺拷貝是常常在面試中會出現的,主要考察你對基本類型和引用類型的理解深度。我在無數次的面試中,應聘者尚未一我的能把這個問題回答狀況,包括不少機構的培訓老師。這篇文章會讓你把基本類型和引用類型的區別搞得清清楚楚,搞清楚這二者的區別,你對任何編程語言的都不怕,由於,這不是js一門語言,是任何編程語言中都須要掌握的知識,並且,在任何編程語言中,二者都是同樣的。面試

深拷貝和淺拷貝主要是針對對象的屬性是對象(引用類型)編程

1、基本類型和引用類型的區別json

一、先了解內存數組

任何編程語言的內存分區幾乎都是同樣的編程語言

內存是存儲數據的,不一樣類型的數據要存儲在不一樣的區域,即分類存放,不一樣的區域做用和功能也不同。就像你家裏的衣櫃同樣,也分了不一樣的區域:如掛西裝的區域,放襪子的區域等等,我相信每一個人都會把這兩個東西放在不一樣的區域。要否則,當你西裝革履地參加一個高檔的宴會,手塞在褲兜裏,掏出來一隻臭襪子,是否是很尷尬!!!哈哈!!!函數

如下爲內存的分區圖。內存分爲四個區域:棧區(堆棧),堆區,全局靜態區,只讀區(常量區和代碼區)。this

https://blog.csdn.net/jiang7701037/article/details/98728249.net

二、基本類型和引用類型在內存上存儲的區別prototype

如今只看棧區和堆區,無論其它區域,也假定只是局部變量。3d

以上函數testf在調用時,

1)、 定義局部變量 age,因爲age是局部變量,因此在棧中申請內存空間,起名爲age,又因爲給age賦的值250是基本類型,因此,值直接存儲在棧中。

2)、定義局部變量arr,因爲arr是局部變量,因此在棧中申請空間,可是arr的內存中存儲的是什麼?因爲給arr賦的值不是基本類型,而是引用類型(new出來的),因此,先在堆中申請空間存放數據 12,23,34,。再把堆區的地址賦給arr。

三、到底什麼是基本類型和引用類型

1)、基本類型:就是值類型,即在變量所對應的內存區域存儲的是值,如:上面的age變量所對應的內存存儲的就是值250.

2)、引用類型:就是地址類型。

何爲地址:地址就是編號,要地址何用,就是爲了容易找到。每一個人的家裏爲何要有一個惟一的地址,就是在郵寄時,可以找到你家。

好比:咱們最先的超市存包的格子,每一個格子都有個編號,你存包時,服務員會把你的東西放在某個格子裏,再把這個格子的編號給你(一個牌子)。你購物完畢取包時,直接給服務員你的牌子(有編號),服務員根據你的編號就會找到你的包。這個編號就是格子的地址。內存也是同樣的,每一個內存都有一個編號,方便cpu查找。要否則,浩瀚的內存海洋,cpu要找到數據靠啥找。

以上的變量arr就是引用類型,arr所對應的內存中存儲着地址,真正的數據是在地址對應的內存區域裏,就像,你填寫簡歷時,會在簡歷的那張紙上寫上你家的地址。簡歷上寫你家地址的地方就至關於arr。而你家是根據這個地址能夠找到的。簡歷上寫你家地址的地方就至關於引用着你家(能夠想象一根無形的線牽引着你家,在簡歷上的這根無形的線,順藤摸瓜就能找到你家)。因此叫作引用類型。

2、基本類型和引用類型在賦值時內存的變化

你能夠認爲,賦值就是在拷貝。

一、基本類型:

二、引用類型:

若是給arr[0]賦值的話,arr1[0]的值也會發生變化,由於,arr和arr1保存着相同的地址,它門兩個引用的數據是共享的。就像你在不少地方(簡歷的那張紙,戶口本上的那張紙)會寫上你的家庭地址。這麼多張紙都引用着你家。根據一張紙上找到你家,給你家放上一百萬的現金(數據改變了,至關於arr[0]=10),再根據另一張紙的地址也找到了你家,你發現你一百萬在(不要給我說被人拿了)

若是在上面的基礎上增長一句代碼:arr[0]=10;那麼內存將會有以下變化:

3、基本類型和引用類型做爲函數參數的區別(這個能夠不看)

一、基本類型做爲函數的參數

二、引用類型做爲函數的參數:

4、深拷貝和淺拷貝:

終於說到了深拷貝和淺拷貝。

其實在第二點已經說到了拷貝,所謂拷貝,就是賦值。把一個變量賦給另一個變量,就是把變量的內容進行拷貝。把一個對象的值賦給另一個對象,就是把一個對象拷貝一份。

一、基本類沒有問題,

由於,基本類型賦值時,賦的是數據(因此,不存在深拷貝和淺拷貝的問題)。

如:

Var x = 100;

Var y = x; //此時x和y都是100;

若是要改變y的值,x的值不會改變。

二、引用類型有問題

由於,引用類型賦值時,賦的值地址(就是引用類型變量在內存中保存的內容),強烈建議把前面的第二點(基本類型和引用類型在賦值時內存的變化)多看幾遍,以保證理解深入。這樣,一勞永逸,之後在碰到任何跟引用類型有關的話題(如:繼承時,父類的屬性是引用類型)都沒有問題。

如:

var arr1 = new Array(12,23,34)

Var arr2 = arr1;//這就是一個最簡單的淺拷貝

若是要改變arr2所引用的數據:arr2[0]=100時,那麼arr1[0]的值也是100。

緣由就是 arr1和arr2引用了同一塊內存區域(以上的第二點中有體現)。

這是最簡單的淺拷貝,由於,只是把arr1的地址拷貝的一份給了arr2,並無把arr1的數據拷貝一份。因此,拷貝的深度不夠

三、用json對象的方式(也是引用類型)來演示淺拷貝和深拷貝

1)、定義一個json對象(對象的屬性也是對象)

00001.

var p = {

"id":"007",

"name":"劉德華",

"books":new Array("三國演義","紅樓夢","水滸傳")//這是引用類型

}

00002.

2)、把該對象p進行復制一份

· (一)淺拷貝

00001.

var p2 = {};

for(let key in p){

p2[key] = p[key];

}

p2.books[0] ="四國";

console.log(p2);

console.log(p);

00002.

在控制檯中打印的結果(p和p2的books[0]都變成了「四國」):

內存:

(二) 深拷貝(初步)

var p2 = {};

for(let key in p){

if(typeof p[key]=='object'){

p2[key]=[];//由於,我上面寫的是數組,因此,暫時賦值一個空數組.

for(let i in p[key]){

p2[key][i] = p[key][i]

}

}else{

p2[key] = p[key];

}

}

p2.books[0] ="四國";

console.log(p2);

console.log(p);

在控制檯中打印的結果(只有p2的books[0]變成了「四國」)

內存:

(三)深拷貝(最終)

3.一、深拷貝_若是屬性都是json對象,那麼用遞歸的方式

//若是對象的屬性是對象(引用類型),屬性的屬性也是引用類型,即層層嵌套不少.怎麼辦,只能遞歸

//以下對象,要複製:

00001.

var p = {

"id":"007",

"name":"劉德華",

"wife":{

"id":"008",

"name":"劉德的妻子",

"address":{

"city":"北京",

"area":"海淀區"

}

}

}

//寫函數

function copyObj(obj){

let newObj={};

for(let key in obj){

if(typeof obj[key] =='object'){//如:key是wife,引用類型,那就遞歸

newObj[key] = copyObj(obj[key])

}else{//基本類型,直接賦值

newObj[key] = obj[key];

}

}

return newObj;

}

let pNew = copyObj(p);

pNew.wife.name="張三瘋";

pNew.wife.address.city = "香港";

console.log(pNew);

console.log(p);

3.二、深拷貝_若是屬性是數組等非鍵值對的對象

就得單獨處理:要麼給數組增長一個自我複製的函數(建議這樣作),要麼單獨判斷。

```

//給數組對象增長一個方法,用來複制本身

Array.prototype.copyself = function(){

let arr = new Array();

for(let i in this){

arr[i] = this[i]

}

return arr;

}

var p = {

"id":"007",

"name":"劉德華",

"books":new Array("三國演義","紅樓夢","水滸傳")//這是引用類型

}

function copyObj(obj){

let newObj={};

for(let key in obj){

if(typeof obj[key] =='object'){//如:key是wife,引用類型,那就遞歸

newObj[key] = obj[key].copyself();

}else{//基本類型,直接賦值

newObj[key] = obj[key];

}

}

return newObj;

}

var pNew = copyObj(p);

pNew.books[0] = "四國";

console.log(pNew);

console.log(p);

```

相關文章
相關標籤/搜索