深拷贝&浅拷贝
2017-07-19 本文已影响16人
尤樊容
数据保存到对象以后会涉及到拷贝的问题,而数据保存的格式多样,这就涉及到了深拷贝和浅拷贝的问题。
产生的原因:
var arr1 = [1,2,3,4,5];
var arr2 = arr1;
arr2[1] = 6;
document.write("arr1: " + arr1 + "<br/>"); //打印结果:arr1: 1,6,3,4,5
document.write("arr2: " + arr2);//打印结果:arr2: 1,6,3,4,5
//打印结果:
//arr1: 1,6,3,4,5
//\arr2: 1,6,3,4,5
用以上方式将数组拷贝到arr2中是直接让两个对象同时指向同一片内存区域,更改其中的一个,另一个也会更改,为了使两个对象保存以后不会互相影响,用下面的一个简单地例子说明:
var arr1 = [1,2,3,4,5];
var arr2 = [];
for(var i = 0; i < arr1.length; i++){
arr2[i] = arr1[i];
}
arr2[1] = 6;
document.write("arr1: " + arr1 + "<br/>");
document.write("arr2: " + arr2);
//打印结果:
//arr1: 1,2,3,4,5
//arr2: 1,6,3,4,5
使用循环将arr1里面的数据一一添加到新的对象中,这样打印出来的结果就不会相互影响,也就是一个浅拷贝。
Array的slice函数也可以实现浅拷贝:
//此方法只针对Array
var arr1 = [1,2,3,4,5];
var arr2 = arr1.slice(1);
arr2[0] = "a";
document.write(arr1 + "<br/>");
document.write(arr2);
//输出结果:
//1,2,3,4,5
//a,3,4,5
但是这个方法也只是浅拷贝的一种,数组有多层的时候也是不行的,例如:
var arr1 = [[1,11],[2,22],[3,33]];
var arr2 = arr1.slice(1);
arr2[0][1] = "a";
document.write(arr1 + "<br/>");
document.write(arr2);
//输出结果:
//1,11,2,a,3,33
//2,a,3,33
Array的concat函数也是浅拷贝,实例如下:
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var arr3 = arr1.concat(arr2);
arr2[1] = "aa";
document.write(arr3);
//输出结果:
//1,2,3,4,5,6
生成的第三个数组是独立的,受arr1和arr2影响。但也只能实现浅拷贝。
浅拷贝只是拷贝了对象最外面的一层,但是并不是所有的对象都是简单到只有一层,所以出现了深拷贝,利用递归将对象深拷贝。
用递归写了一个例子:
var object1 = [1,2,3,4,{a:"aaa", b:"bbb"},6,7,[8,9,{c:"ccc", d:"ddd"}]];
function deepCopy(obj, newObj) {
var newObj = newObj || ((obj.constructor === Array) ? [] : {});
for (var i in obj) {
if (typeof obj[i] === 'object') {
newObj[i] = (obj[i].constructor === Array) ? [] : {};
deepCopy(obj[i], newObj[i]);
} else {
newObj[i] = obj[i];
}
}
return newObj;
}
var arr = deepCopy(object1);
arr[4].a = "ccc";
console.log(object1);// [1,2,3,4,{a:"aaa", b:"bbb"},6,7,[8,9,{c:"ccc", d:"ddd"}]]
console.log(arr);// [1,2,3,4,{a:"ccc", b:"bbb"},6,7,[8,9,{c:"ccc", d:"ddd"}]]
在拷贝的时候检查数据的格式,然后分情况拷贝。这样的方法可以提高代码的重用,在数据格式未知的情况下,避免出错,但是这样写在某些情况下也会降低代码执行的效率,比如数据已知并且单一的情况下,浅拷贝就可以满足,并且可以提高代码执行的效率。