浅拷贝
之前文章提到,在定义一个对象或数组时,变量存放的往往只是一个地址。当我们对堆内存
中的对象复制时,如果属性是对象或数组时,这时候我们拷贝的只是一个栈内存
的指针
。因此b对象在访问该属性时,会根据指针寻找到a对象指向的堆内存对象,两者的属性值会指向同一内存空间。
var a = {
key1:"11111"
}
function Copy(p) {
var c = {};
for (var i in p) {
c[i] = p[i];
}
return c;
}
a.key2 = ['小辉','小辉'];
var b = Copy(a);
b.key3 = '33333';
alert(b.key1); //1111111
alert(b.key3); //33333
alert(a.key3); //undefined
//对象中key1属性是字符串,key2属性是数组。a拷贝到b,12属性均顺利拷贝。给b对象新增一个字符串类型的属性key3时,b能正常修改,而a中无定义。说明子对象的key3(基本类型)并没有关联到父对象中,所以undefined。
b.key2.push("大辉");
alert(b.key2); //小辉,小辉,大辉
alert(a.key2); //小辉,小辉,大辉
但是,若修改的属性变为对象或数组时,那么对象之间就会发生关联。从以上弹出结果可知,对b对象进行修改,a、b的key2
属性值(数组)均发生了改变。其在内存的状态,可以用下图来表示。
深拷贝
不希望对象之间产生关联,那么这时候可以用到深拷贝。既然属性值类型是数组和或对象时只会传址,那么我们就用递归来解决这个问题,把要复制的对象中所有属于对象的属性类型都遍历赋给新对象即可。
function Copy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === 'object') {
c[i] = (p[i].constructor === Array) ? [] : {};
Copy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}
a.key2 = ['小辉','小辉'];
var b={};
b = Copy(a,b);
b.key2.push("大辉");
alert(b.key2); //小辉,小辉,大辉
alert(a.key2); //小辉,小辉
过程如下图