转载网址:https://zhuanlan.zhihu.com/p/48269135
起因:
社区提问
评论区
快要到下班时间,摸鱼逛论坛的时候,发现有人问了这个问题。就整理下吧。
问:为什么会产生深度复制和浅度复制?
答:js有两种大类的类型:基本类型(undefined、Null、Boolean、Number和String)和引用类型(Object、Array和Function),基本类型的复制是不会产生深度复制和浅度复制问题,当使用引用类型进行复制的时候,其实复制的是指向内存值的指针,并没有真实复制其数据(浅复制)。
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = obj1;
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 100, c: 30 } <-- b 被改到了
console.log(obj2);
// { a: 10, b: 100, c: 30 }
问:什么是深度复制?
答:深度复制就是遍历复制目标的所有的属性,并复制属性指向的动态分配的内存。当对象和它所引用的对象一起复制时即深度复制。深度复制相比于仅复制指针的浅度复制速度较慢并且花销较大。好处就是不会发生改变原始的值的情况。
问:如何进行深度复制?
答:
第一种:对于数组在ES6种可以使用Array.from(arr);
var arr1=[1,2,3];
var arr2=Array.from(arr1);
arr1.push(4);
alert(arr1); //1234
alert(arr2); //123
arr2.push(5);
alert(arr1); //1234
alert(arr2); //1235
第二种:也可以使用ES6中的扩展运算符 ...
var arr1=[1,2,3];
var arr2=[...arr1];
arr1.push(4);
alert(arr1); //1234
alert(arr2); //123
arr2.push(5);
alert(arr1); //1234
alert(arr2); //1235
第三种:递归复制所有属性
对于一个对象来说,由于可能有多层结构,所以我们可以使用递归来解决这个问题
function deepClone(data){
var type = getType(data);
var obj;
if(type === 'array'){
obj = [];
} else if(type === 'object'){
obj = {};
} else {
//不再具有下一层次
return data;
}
if(type === 'array'){
for(var i = 0, len = data.length; i < len; i++){
obj.push(deepClone(data[i]));
}
} else if(type === 'object'){
for(var key in data){
obj[key] = deepClone(data[key]);
}
}
return obj;
}
第四种:也可以使用Object.create()方法
var newObj = Object.create(oldObj)
第五种:也可以使用JSON.parse和JSON.stringify(缺点不能深拷贝值为函数的对象属性)
var target = JSON.parse(JSON.stringify(source));
简单归纳一下:
对于数组,可以直接使用Array.from(arr)或者...扩展运算符来进行深拷贝。
对于对象,可以使用JSON.parse和JSON.stringify来进行深拷贝,但是不能拷贝值为函数的对象属性(在node环境,返回undefeated)。如果对象属性是一个函数可以使用Object.create(obj)来进行深拷贝。