首先我们来讲一下赋值关系和引用关系
- 赋值关系
var a = 5;
var b =a;
b+ = 3;
alert(b);//8
alert(a);//5
a和b是简单的赋值关系,这种赋值关系存在于基本类型中
- 对于函数和对象,存在的不是简单的赋值关系,而是引用关系
我们来看两种情况
var a = [1,2,3]
var b = a;
b.push(4);
alert(a)//1,2,3,4
alert(b)//1,2,3,4
在这种情况下,a和b共用一个内存空间。就像我们c语言中的指针。用一种更形象的说法:a与b都有一个存库的门,所以他们都能改变这个仓库,都改变的是同一个仓库。
var a = [1,2,3];
var b = a;
b = [1,2,3,4];
alert(a)//1,2,3
alert(b)//1,2,3,4
这种情况就和刚才有点不同了。你或许会想,ab不是共用一个内存吗,为什么b变了a不跟着变。
在这里我们就要注意这两句的区别了
b.push(4);
b = [1,2,3,4];
前面一句是用数组方法向仓库里放了一个4,所以ab呈现出来的都是1234毕竟他们用的是一个仓库。而后面一句b = [1,2,3,4];而是创建了一个新数组,重新放入1,2,3,4,这时候他已经和a没有关系了,他放入的前三个数甚至可以不是和a一样的123了。
我觉得这两个例子就像这样的一个故事:a和b是一对父子,小时候b和爸爸a一起生活,有时为家里添置一点小家具;后来b长大了就自己买房子了,自己可以把房子装修得完全不一样了。(个人理解,帮助记忆而已,不必深究)
了解了对象的引用关系,下面我们来谈谈怎样复制对象
对象的拷贝有两种方式,我们称为深拷贝和浅拷贝,浅拷贝就是只复制最表面的那一层对象,我们来看下面这个例子
var obj = {
a:10
}
function copy() {//浅拷贝
var newObj = {};
for(var attr in obj) {
newObj[attr] = obj[attr];
}
return newObj;
}
var obj2 = copy(obj);
obj2.a = 20;
alert(obj.a)//10
在这个例子中,我定义了一个拷贝的函数,这个函数的思路是:把所有a中的属性都复制到b中去,然后返回一个新对象。因为obj对象中只有一层,所以obj2拷贝成功。
我们再来看看原对象不止一层的情况
var objX = {
a:{b:10}
}
var objY = copy(objX);
objy.a.b = 20;
alert(objX.a.b)//20 复制失败
这里我们还是使用的上面的拷贝函数。我们可以看到,这一次就拷贝失败了。这就是我说的浅拷贝这能拷贝一层对象。
下面我们来看深拷贝
深拷贝其实拷贝的原理和浅拷贝是一样的,我们需要做到的就是把每一层对象都拷贝过去。这里我采用递归的方法。
递归应该大家都知道,到可能概念模模糊糊,所以我先简单的介绍一下递归。
- 递归
递:传递
归:回到之前的位置
image.png我们来看一个求阶层的例子
function test(n) {
return n*test(n-1);
}
我们要在它返回的时候再去执行它本身,每次传进的参数会小1.当然,这传递的运算必须要有一个结束的时候,所以我们要进行判断什么时候结束
function test(n) {
if(n==1) {
return 1;
}
return n*test(n-1);
}
这里在n=1时函数就执行结束了。
所以总结递归的两个点
- 函数调用函数自身,执行递的动作
- 最后一次判断一个终止条件,可以执行的动作
然后我们的深拷贝就开始了
function deepCopy(obj) {
if(typeof obj != 'object') {
return obj;
}
var newObj = {};
for(var attr in obj) {
newObj[attr] = deepCopy(obj[attr]);
}
return newObj;
}
在这里,我们一层一层的往下剥,剥到不是对象的时候就停止了,也就实现了深拷贝
如果你对我的文章有想说的话,欢迎qq交流:425910502.在这里附上qq主要是因为经常在网上看一些文章,有问题想问作者又得不到作者即使的回复,让人很懊恼,虽然我的文章并不会被很多人看到,但我要对看到我文章的人负责。
网友评论