標籤:
所謂深拷貝,就是子物件不緊繼承父物件的非引用屬性,還能繼承父物件的引用屬性(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很好的驗證了淺拷貝和深拷貝的區別
JS深拷貝繼承