说到深浅拷贝的问题,其实就是基本类型和引用类型数据拷贝的问题,再深一点就是栈内存和堆内存的区别。
栈内存
保存基本数据类型或者引用类型数据的地址指针。
堆内存
保存对象本身。
所谓的深拷贝就是在内存中单独为该变量开辟一个存储空间。所以对于基本数据类型来说他的任何赋值都深拷贝,因为在栈内存中,数据的大小是固定,不可变的,变量一旦声明就会在内存中在栈内存中开辟一个新的空间。常说的深拷贝是针对于引用类型的。引用类型在栈内存中只保存了一个指向堆内存的指针,所以一般我们在将一个引用类型赋值给另外一个变量的时候,实际上是将这个引用类型在栈内存中指针赋值给了这变量,而最终这个变量指向的堆内存中的同一个对象。
举例:
var obj1 = {name:"wangyy"};
var obj2 = obj1;
obj2.name="wangjunjie";
console.log("obj1:",obj1);
console.log("obj2:",obj2);
运行结果:obj1:{name:"wangjunjie"}
obj2:{name:"wangjunjie"}
发现在改obj2的时候obj1也跟着改变了,这就是他们指针指向的是同一个内存对象,所以改也是改的同一个对象。但这不是我们希望的赋值 ,我们希望在赋值结束后彼此之前再无瓜葛,那我们应该怎样实现呢?
好了不多说了,上代码了。
方法一:
Object.assign();
var target = {};
var source = {name:"wangyy"}
Object.assign(target,source);
target.name="wangjunjie";
console.log("target:",target);
console.log("source:",source);
运行结果:target:{name:"wangjunjie"}
source:{name:"wangyy"}
貌似可以实现深拷贝,在这种情况下也确实能达到我们的目的,但是这种方式是有缺陷的,当对象的属性值也是一个对象的时候,它几现原形了。
var target = {};
var source = {name:"wangyy",family:{mother:"wuxl","father":"wangxy"}}
Object.assign(target,source);
target.family.sister="wanghm";
console.log("target:",target);
console.log("source:",source);
通过运行结果可以发现Object.assign只能对于像上面那种简单对象可以实现深拷贝,对于复杂对象就无能为力了。
方法二:
将对象转成字符串:
var target = {};
var source = {name:"wangyy",family:{mother:"wuxl","father":"wangxy"}}
target = JSON.parse(JSON.stringify(source ))
target.family.sister="wanghm";
console.log("target:",target);
console.log("source:",source);
哎!好像可以实现呢,而且也是想对比较号实现的。但是如果出爱心下面这种情况就凉凉了
var target = {};
var source = {
name:"wangyy",
family:{
mother:"wuxl",
father:"wangxy",
}
}
target = JSON.parse(JSON.stringify(source ))
target.family.sister="wanghm";
console.log("target:",target);
console.log("source:",source);
运行后我们发现source中的func属性不见了。所以这种方式还是有局限性的,必须是标准格式的JSON数据。
方法三:
看来向上面这种一步到位实现深拷贝是不显示了,那下面就专门写一个深拷贝的方法来实现:
function deepClone(data){
if(!data|!(datainstanceof Object)|(typeof data=="function")){
return data||undefined;
}
var constructor = data.constructor;
var result = new constructor();
for(var key in data){
if(data.hasOwnProperty(key)){
result[key]=deepClone(data[key]);
}
}
return result;
}
本质就是区分基本数据类型和引用数据类型,然后进行递归操作,over!