天天看点

关于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:"女"}}
           

此时可以看到不会再出现互相影响的情况,这就是深拷贝。通过深拷贝使得拷贝和被拷贝的对象所有属性都不再指向同一个引用。

继续阅读