在计算机中,有两种存储数据的方式,一种是字符串类型,另一种是引用类型。其中字符串类型是存储在内存的栈中,而引用类型是存储在内存的堆中,栈中的变量通过指针可以指向堆中的引用类型对象。
浅拷贝指将对象B直接赋值给对象B,两者在栈中是两个变量,却同时指向堆中的同一个对象。当改变其中一者时,另一者也同步进行改变。
let obj1 = {a:1};
let obj2 = obj1;
obj2.a = 10;
console.log(obj1); //{a:10}
console.log(obj2); //{a:10}
可以看出,当进行完对象的赋值操作后,如果在改变赋值对象的时候不希望破坏被赋值对象,这种方式不能达到预期要求,这就是浅拷贝。
深拷贝是指根据原对象在堆中创建一个新的引用类型,在栈中创建一个变量通过指针指向这个新的引用类型,因而与原对象完全脱离了关联,当改变其中一者时,另一者不随其进行改变。
深拷贝的方式有以下几种:
1、ES6方法;
let obj1 = {a:1,b:2,c:3};
let obj2 = {...obj1};
obj2.a=100;
console.log(obj2);//{a:100,b:2,c:3}
console.log(obj1);//{a:1,b:2,c:3}
这种方式不适合引用类型嵌套引用类型的方式。即:
let obj1 = {
a:{
b:1
}
}
let obj2 = {...obj1};
obj2.a.b = 100;
console.log(obj2); //{a:{b:100}}
console.log(obj1);//{a:{b:100}}
2、JSON.stringfy和JSON.parse,这种方式同样不适合引用类型嵌套引用类型的方式
let obj1 = {a:1,b:2,c:3};
let obj2 = JSON.parse(JSON.stringfy(obj1));
obj2.a=100;
console.log(obj2);//{a:100,b:2,c:3}
console.log(obj1);//{a:1,b:2,c:3}
3、Object.assign(),这种方式同样不适合引用类型嵌套引用类型的方式
let obj1 = {a:1,b:2,c:3};
let obj2 = Object.assign({},obj1);
obj2.a=100;
console.log(obj2);//{a:100,b:2,c:3}
console.log(obj1);//{a:1,b:2,c:3}
4、通过jQuery.extend或loadash的cloneDeep
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
5、最靠谱的一种方式当然是通过手写函数来实现,适合各种类型的对象。
function deep_clone(obj){
if(typeof obj!=='object') return obj;
let newObj = obj.constructor===Array?[]:{};
for(let i in obj){
if(typeof obj[i]==='object'){
newObj[i]=deep_clone(obj[i]);
}else{
newObj[i]=obj[i];
}
}
return newObj;
}
let obj = {a:1};
let obj2 = deep_clone(obj);
obj2.a=100;
console.log(obj2);//{a:100};
console.log(obj);//{a:1};
如果文中有不妥之处,欢迎各位大神指正。