js对象的直接赋值、浅拷贝与深拷贝
最近做到一个用编程实现js对对象的深拷贝浅拷贝的问题,下面就来总结一下直接赋值,浅拷贝,深拷贝的差别,以及代码实现方式!!
直接赋值
把一个对象A赋值给一个对象B相当于把一个对象B的地址指向对象A地址,所以,他们实际上是同一个对象。以图1直接赋值的例子,person对象中有两个属性,一个是name,一个是对象属性address;为什么设置一个对象属性呢?下面会涉及到浅拷贝和深拷贝问题,这也是他们之间的区别。
严格相等运算符"==="来检测二者是否指向同一个地址
结论:
无论修改赋值后的对象B的非对象属性还是对象属性,都会影响原对象A的对应的属性
浅拷贝
修改赋值后的对象B的非对象属性,不会影响原对象A的非对象属性;修改赋值后的对象B的对象属性,却会影响原对象A的对象属性。
浅拷贝的2种方法(ES6语法):
- Object.assign(target, sources)
- 扩展运算符(…),例:var copy= { …person };
深拷贝
深拷贝会另外拷贝一份一个一模一样的对象,但是不同的是会从堆内存中开辟一个新的区域存放新对象,新对象跟原对象不再共享内存,修改赋值后的对象b不会改到原对象a。即深拷贝,修改赋值后的对象b的非对象属性,不会影响原对象a的非对象属性;修改赋值后的对象b的对象属性,也不会影响原对象a的对象属性。而且,二者不指向同一个对象。
方法一:利用 JSON 对象中的 parse 和 stringify;
var obj1 = {
name: "cat",
show:function(){
console.log(this.name);
}
};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = "pig";
console.log(obj1.name); //cat
console.log(obj2.name); //pig
obj1.show(); //cat
obj2.show(); //函数被丢失,报错
JSON.stringify()会导致一系列的问题,因为要严格遵守JSON序列化规则:原对象中如果含有Date对象,JSON.stringify()会将其变为字符串,之后并不会将其还原为日期对象。或是含有RegExp对象,JSON.stringify()会将其变为空对象,属性中含有NaN、Infinity和-Infinity,则序列化的结果会变成null,如果属性中有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失,因为不支持。
方法二:利用递归来实现每一层都重新创建对象并赋值
var obj1 = [{
name:'cat',
address:{city:'北京',area:'昌平',tel:[1,2,3]},
show: function(){
console.log(this.address.city+''+this.name);
}
}]
var obj2={
arr1:[1,{arr2:[1,5,7]}],
message:'你好啊'
}
function deepClone(obj){
//判断obj为object还是array,因为array也是object类型的,但是object不是array类型的
//需要先行判断是否因为array类型
let objClone = Array.isArray(obj)?[]:{};
//obj存在,且obj类型为object(数组类型也为object)
if(obj && typeof obj ==='object'){
//遍历对象中的每个子元素
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断obj子元素是否为对象,如果是,递归复制
if(obj[key] && typeof obj[key] ==='object'){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,就简单复制就可以了
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
console.log(typeof [1,2,2]); //object
console.log(deepClone(obj1));
console.log(deepClone(obj2));