天天看點

關于js中淺拷貝和深拷貝的問題

首先在說淺拷貝和深拷貝之前我們需要了解一下在javascript裡面包含兩種不同的資料類型值:基本資料類型和引用資料類型。

基本資料類型有:Boolean、Null、Undefined、Number、String、Symbol

引用資料類型有:Object、Array、Function、RegExp、Date等

基本資料類型:名值存儲在棧記憶體中占據固定大小的空間;

引用資料類型:名存在棧記憶體中,值存在堆記憶體中,棧記憶體會提供一個引用位址指向堆記憶體中的值。

棧:是一種連續儲存的資料結構,具有先進後出的性質。

堆:是一種非連續的樹形儲存資料結構,每個節點有一個值,整棵樹是經過排序的。

這裡不需要用到這麼抽象的解釋,簡單說就是計算機裡的兩種記憶體配置設定形式。

總之就是計算機裡的兩種記憶體配置設定形式。

我們要說的淺拷貝和深拷貝主要是針對對象(引用資料類型)來說的,簡單對象一般都是淺拷貝,這種對象一般它的屬性都是一層,不包含嵌套屬性

例如 :

var obj = {name:"qws",age:19}    複制對象obj,一般是這樣  var obj2 = obj  此時obj2 複制了obj  這個時候改變obj中的屬性的值,obj2中的值也會随之改變,同樣obj2中屬性值的改變也會影響到對象obj,這是因為這兩個對象的變量共用同一個引用。如果我想保持兩個對象的獨立性那麼就要用所要說的淺拷貝和深拷貝。

深拷貝和淺拷貝主要是為了解決對象直接指派後依然共用同一個引用的問題,它們之間會互相影響

下面我們寫一個淺拷貝的例子做一下實驗:

var obj={
	name:"bill",
	age:19
}

function copy(obj){
	var newobj={};
	for(itme in obj){
		newobj[itme] = obj[itme];
	}
	return newobj;
}

var obj2 = copy(obj);
console.log(obj2); //{name:"bill",age:19}由此可見拷貝成功

obj.name = "keke";

console.log(obj2); //{name:"keke",age:19} 改變obj2的屬性name的值
console.log(obj); 
//{name:"bill",age:19} 對象obj沒把改變,說明拷貝沒有問題,連個對象不會互相影響它們目前不是是用的同一個引用
           

上面的被拷貝的對象很簡單隻有一層,是以我們很簡單就實作了,但是如果對象内部嵌套了子對象這種方法就會出現問題

例如:

var obj={
	name:"bill",
	age:19,
	msg:{
		address:"北京朝陽",
		sex:"男"
	}
}

function copy(obj){
	var newobj={};
	for(itme in obj){
		newobj[itme] = obj[itme];
	}
	return newobj;
}

var obj2 = copy(obj);
console.log(obj2); //{name:"bill",age:19,msg:{address:"北京朝陽",sex:"男"}}由此可見拷貝成功

obj2.msg.sex = "女";
console.log(obj); //{name:"bill",age:19,msg:{address:"北京朝陽",sex:"女"}}
           

有上面代碼最後的運作結果可以看到,當obj2改變内部子對象msg的屬性sex的值時,被拷貝對象obj内的age也被改變,如果我們隻是改變name屬性的值那就沒有關系,不會互相影響,但是如果改變深一層的子對象就會出問題。這時淺拷貝就不能解決這種關聯關系。那我們就把代碼進行一下改進,這要用到遞歸的思想

var obj={
	name:"bill",
	age:19,
	msg:{
		address:"北京朝陽",
		sex:"男"
	}
}

function deepcopy(obj){
	var newobj={};
	for(itme in obj){
		if(typeof obj[itme] === 'object' && obj[itme] !== null){
			newobj[itme] = deepcopy(obj[itme]);//遞歸
		}else{
			newobj[itme] = obj[itme];
		}		
	}
	return newobj;
}

var obj2 = deepcopy(obj);
console.log(obj2); //{name:"bill",age:19,msg:{address:"北京朝陽",sex:"男"}}由此可見拷貝成功

obj2.msg.sex = "女";
console.log(obj); //{name:"bill",age:19,msg:{address:"北京朝陽",sex:"男"}}
console.log(obj2);//{name:"bill",age:19,msg:{address:"北京朝陽",sex:"女"}}
           

此時可以看到不會再出現互相影響的情況,這就是深拷貝。通過深拷貝使得拷貝和被拷貝的對象所有屬性都不再指向同一個引用。

繼續閱讀