所謂深拷貝,就是子對象不緊繼承父對象的非引用屬性,還能繼承父對象的引用屬性(Object,Array),當子對象對繼承的引用類型屬性做修改時,父對象的引用類型不會被修改。
我們先寫個淺拷貝的封裝函數:
function extendCopy(parent){ var child={}; for(var i in parent){ child[i]=parent[i]; } child.uber=parent; return child; }
接下來寫個深拷貝的封裝函數:
function deepCopy(p,c){ var c=c||{}; for(var i in p){ if(typeof p[i]==="object"){ c[i]=(p[i].constructor===Array)? [] : {};
deepCopy(p[i],c[i]); }else{ c[i]=p[i]; } } return c; }
分析兩個函數有何不同,extendCopy方法是將父對象的屬性和方法逐個的拷貝給子對象,當遇到引用類型的屬性時,比如數組,那么若對子對象拷貝而來的數組進行重寫時,父對象對應的數組也會隨之改變,因為他們指向的是同一地址。
而deepCopy方法:
舉個栗子:
var parent={
score:[1,2,3,4];
}
var child=deepCopy(parent);
執行deepCopy函數后,當執行到
if(typeof parent[score]==='object')時,
child[score]=[];
再執行deepCopy(parent[score],child[score]);
此時typeof p[i]就不是'object'類型了,而是number類型,
所以
child[score][1]=parent[score][1]=1;
child[score][2]=parent[score][2]=2;
child[score][3]=parent[score][3]=3;
child[score][4]=parent[score][4]=4;
在return child[score];
這樣就完成了深拷貝,child[score]和parent[score]不是指向同一個地址了。但此時兩者值相同,只是地址不同,若再對child[score]做修改,parent[score]不會有任何變化。
我們來試驗一下:
var Shape={ color:"blue", name:"shape", size:[1,2,3,4], getName:function(){ return this.name; } } var circle=deepCopy(Shape); var tran=extendCopy(Shape); circle.size.push(5,6); console.log(circle.size); //[1,2,3,4,5,6] console.log(Shape.size);//[1,2,3,4] 深拷貝父對象值沒有變化 tran.size.push(5,6,7,8); console.log(circle.size); //[1,2,3,4,5,6] console.log(tran.size);//[1,2,3,4,5,6,7,8] console.log(Shape.size); //[1,2,3,4,5,6,7,8] 淺拷貝隨着tran.size的改變,Shape.size也會隨之改變,
上述demo很好的驗證了淺拷貝和深拷貝的區別