一、深拷贝和浅拷贝的概念
举个栗子:
var a = {name:'Jack'};
var b = a;
b.name = 'Peter';
console.log(a.name) //'Peter'
从以上代码可以看出,当a是一个对象的时候,将a赋值给b,则b的属性改变之后a的属性也会相应的改变(因为它们指向了同一块内存),这就是浅拷贝。
与之相反的,若将a的属性复制到b,而b重新指向另一块内存,则b里的属性变化时,a的属性将不会被改变,这就是深拷贝。
并且,JavaScript中的七种数据类型中,基本类型(String、Number、Boolean、Symbol、null、undefined)在拷贝的时候,结果都符合深拷贝的定义,因此不在我们的讨论范围。
二、实现浅拷贝
1、直接赋值
var obj1 = {a:1,b:2};
var obj2 = obj1;
obj2.a = 3;
console.log(obj2)//{a:3,b:2}
console.log(obj1)//{a:3,b:2}
2、用Object.assign()
来实现
var obj1 = {a:1,b:{b1:2,b2:3}};
var obj2 = Object.assign({},obj1);
obj2.b.b1 = 4;
console.log(obj2)//{a:1,b:{b1:4,b2:3}}
console.log(obj1)//{a:1,b:{b1:4,b2:3}}
值得注意的是,当obj1里的数据只有一层时,Object.assign()
是深拷贝
var obj1 = {a:1,b:2};
var obj2 = Object.assign({},obj1);
obj2.a = 3;
console.log(obj2)//{a:3,b:2}
console.log(obj1)//{a:1,b:2}
三、实现深拷贝
1、用递归实现
var Jack = {
name : 'Jack',
nationality :'US',
friends:['Sally','Ryan']
};
function deepCopy(o,c){
var c = c || {}
for(var i in o){
if(typeof o[i] === 'object'){
if(o[i].constructor === Array){
c[i] =[]
}else{
c[i] = {}
}
deepCopy(o[i],c[i])
}else{
c[i] = o[i]
}
}
return c
};
var Peter = {};
deepCopy(Jack,Peter);
Peter.name = 'Peter';
console.log(Peter) //{name:'Peter',nationality:'US',friends:['Sally','Ryan']}
console.log(Jack)//{name:'Jack',nationality:'US',friends:['Sally','Ryan']}
2、用JSON.parse()
和JSON.stringfy()
来实现
var target = {a: 1, b: 1, c: {c1: 11, c2: 12, c3: 13}};
var deepCopy = JSON.parse(JSON.stringify(target));
deepCopy.a = 2;
deepCopy.c.c1 = 21;
console.log(target); // {a: 1, b: 1, c: {c1: 11, c2: 12, c3: 13}}
console.log(deepCopy); // {a: 2, b: 1, c: {c1: 21, c2: 12, c3: 13}}
console.log(target === deepCopy); // false
注:JSON.parse()
和JSON.stringfy()
能够正确处理的只有String、Number、Array等能够被json表示的数据类型,不能被json表示的会丢失。
var target = {a:1,b:1,c:function(){console.log('hi')}};
var deepCopy = JSON.parse(JSON.stringfy(target));
console.log(deepCopy)//{a:1,b:1}
3、用jQuery.extend()
来实现
var target = {a:1,b:1,c:{c1:11,c2:12,c3:13}};
var deepCopy = $.extend(true,{},target)
deepCopy.c.c2 = 22
console.log(deepCopy)//{a:1,b:1,c:{c1:11,c2:22,c3:13}}
console.log(target)//{a:1,b:1,c:{c1:11,c2:12,c3:13}}