2

浅拷贝


之前文章提到,在定义一个对象或数组时,变量存放的往往只是一个地址。当我们对堆内存中的对象复制时,如果属性是对象或数组时,这时候我们拷贝的只是一个栈内存指针。因此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属性值(数组)均发生了改变。其在内存的状态,可以用下图来表示。

clipboard.png


深拷贝

不希望对象之间产生关联,那么这时候可以用到深拷贝。既然属性值类型是数组和或对象时只会传址,那么我们就用递归来解决这个问题,把要复制的对象中所有属于对象的属性类型都遍历赋给新对象即可。

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);    //小辉,小辉

过程如下图

clipboard.png


Yagamilight
29 声望0 粉丝

在此刻,苍蓝的风正轻轻叩醒我的心门