浅谈深浅复制
在开发过程中,我们常常会遇到对复杂对象中数据的复制。这时候就存在两种情况,一个是复制引用,一个是复制实例。这也就是浅复制和深复制。
什么是深度复制和浅度复制呢?
深度复制和浅度复制都是针对像Array、Object等复杂对象而言的。
对对象而言,浅复制是指是对对象地址的复制,没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变;而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
浅复制
1 | var testArray = [0,1,2] |
由上面的例子可以看出,当改变复制数组中的值时,原来的数组值也会被改变。
深度复制
深度复制情况比较复杂
1.slice()和concat()方法
Array的slice和concat方法都会返回一个新的数组实例,但是这两个方法对于数组中的对象元素却没有执行深复制,而只是复制了引用了,因此这两个方法并不是真正的深复制,通过以下代码进行理解:1
2
3
4
5
6
7
8var array = [1,2,3];
var array_shallow = array;
var array_concat = array.concat();
var array_slice = array.slice(0);
array[0] = 2;
console.log(array_shallow);//[2,2,3]
console.log(array_concat);//[1,2,3]
console.log(array_slice)//[1,2,3]
这里的复制只复制了一层,如果有多层属性的话,还是指向同一个内存地址,看下方的例子:1
2
3
4
5
6
7
8
9
10
11var array = [1, [1,2,3], {name:"array"}];
var array_concat = array.concat();
var array_slice = array.slice(0);
//改变array_concat中数组元素的值
array_concat[1][0] = 5;
console.log(array[1]); //[5,2,3]
console.log(array_slice[1]); //[5,2,3]
//改变array_slice中对象元素的值
array_slice[2].name = "array_slice";
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice
这里的例子可以看出不是真正的深度复制,只是对对象进行了引用
2.Object.assign()
看下方的例子,相信你大概就明白了这个方法到底是深度复制还是浅复制1
2
3
4
5var obj = {a:1,b:2};
var objclone = Object.assign({},obj);
obj.c = 3;
console.log(obj); //输出 {a:1,b:2,c:3}
console.log(objclone); //输出{a:1,b:2}
再来一个~1
2
3
4
5
6
7
8
9
10
11
12let obj = {
a: 1,
b: 2,
c: {
age: 30
}
};
var objclone = Object.assign({},obj);
console.log('objclone: ', objclone);
obj.c.age = 45;
console.log('After Change - obj: ', obj.c.age); // 45 - This also changes
console.log('After Change - objclone: ', objclone.c.age); // 45
所以Object.assign() 只是一级属性复制,比浅拷贝多深拷贝了一层而已。对于多层属性的复制,它也是属于浅复制。
3.JSON实现
JSON对象下有两个方法,一是将JS对象转换成字符串对象的JSON.stringify方法;一个是将字符串对象转换成JS对象的JSON.parse方法。这两个方法结合使用可以实现对象的深复制。也就是说,当我们需要复制一个obj对象时,可以先调用JSON.stringify(obj),将其转换为字符串对象,然后再调用JSON.parse方法,将其转换为JS对象。就可以轻松的实现对象的深复制
看下方例子1
2
3
4
5
6
7
8
9
10
11var obj = {
a: 1,
b: 2,
c: {
age: 30
}
};
var copyObject = JSON.parse(JSON.stringify(obj));
copyObject.c.age = 45;
console.log(obj) //obj={a:1,b:2,c:{age:30}}
console.log(copyObject) //copyObject={a:1,b:2,c:{age:45}}
使用这种方式实现深复制有一个缺点就是必须给JSON.parse方法传入的字符串必须是合法的JSON,否则会抛出错误
4.采用递归解决
1 | var testObject = { |
这种方法的缺点是对于数据庞大的对象运行效率较低
以上是对深度复制和浅度复制的理解,如果有不对的地方欢迎指正哟,相互学习讨论~