首先我們來講一下賦值關系和引用關系
- 賦值關系
var a = 5;
var b =a;
b+ = 3;
alert(b);//8
alert(a);//5
a和b是簡單的賦值關系,這種賦值關系存在于基本類型中
- 對于函數(shù)和對象,存在的不是簡單的賦值關系,而是引用關系
我們來看兩種情況
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不跟著變。
在這里我們就要注意這兩句的區(qū)別了
b.push(4);
b = [1,2,3,4];
前面一句是用數(shù)組方法向倉庫里放了一個4,所以ab呈現(xiàn)出來的都是1234畢竟他們用的是一個倉庫。而后面一句b = [1,2,3,4];而是創(chuàng)建了一個新數(shù)組,重新放入1,2,3,4,這時候他已經和a沒有關系了,他放入的前三個數(shù)甚至可以不是和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
在這個例子中,我定義了一個拷貝的函數(shù),這個函數(shù)的思路是:把所有a中的屬性都復制到b中去,然后返回一個新對象。因為obj對象中只有一層,所以obj2拷貝成功。
我們再來看看原對象不止一層的情況
var objX = {
a:{b:10}
}
var objY = copy(objX);
objy.a.b = 20;
alert(objX.a.b)//20 復制失敗
這里我們還是使用的上面的拷貝函數(shù)。我們可以看到,這一次就拷貝失敗了。這就是我說的淺拷貝這能拷貝一層對象。
下面我們來看深拷貝
深拷貝其實拷貝的原理和淺拷貝是一樣的,我們需要做到的就是把每一層對象都拷貝過去。這里我采用遞歸的方法。
遞歸應該大家都知道,到可能概念模模糊糊,所以我先簡單的介紹一下遞歸。
- 遞歸
遞:傳遞
歸:回到之前的位置

我們來看一個求階層的例子
function test(n) {
return n*test(n-1);
}
我們要在它返回的時候再去執(zhí)行它本身,每次傳進的參數(shù)會小1.當然,這傳遞的運算必須要有一個結束的時候,所以我們要進行判斷什么時候結束
function test(n) {
if(n==1) {
return 1;
}
return n*test(n-1);
}
這里在n=1時函數(shù)就執(zhí)行結束了。
所以總結遞歸的兩個點
- 函數(shù)調用函數(shù)自身,執(zhí)行遞的動作
- 最后一次判斷一個終止條件,可以執(zhí)行的動作
然后我們的深拷貝就開始了
function deepCopy(obj) {
if(typeof obj != 'object') {
return obj;
}
var newObj = {};
for(var attr in obj) {
newObj[attr] = deepCopy(obj[attr]);
}
return newObj;
}
在這里,我們一層一層的往下剝,剝到不是對象的時候就停止了,也就實現(xiàn)了深拷貝
如果你對我的文章有想說的話,歡迎qq交流:425910502.在這里附上qq主要是因為經常在網上看一些文章,有問題想問作者又得不到作者即使的回復,讓人很懊惱,雖然我的文章并不會被很多人看到,但我要對看到我文章的人負責。