深度克隆與淺度克隆

上星期再次研究了一下以前不太清楚的深度克隆,經過連續的寫了3次之後終於清晰了一點,記錄一下思路。

show me my code

var user={
    name:'姓名',
    gender:'性別',
    Tags:['標籤1','標籤2']
}

顧名思義,淺度克隆就是指複製啦~

Object.prototype.clone=function(){
    var newObj={};
    for(var key in this){
        if(this.hasOwnProperty(key)){
            newObj[key]=this[key];
        }
    }
    return newObj;
};
var jack=user.clone();
jack.name='jack';
jack.gender='男';
jack.Tags.push('男神');

結果如下:
淺度克隆結果

ok,我們這裏就完成了淺度克隆了,由於我是對整個Object的原型寫函數來繼承的,所以我在循環內判斷了一下屬性是否爲自身的自有屬性,是的話才能複製,解決了會繼承複製clone函數的小問題,如果不判斷,在結果中會出現clone函數,因爲我們這裏是對所有對象原型寫的繼承函數。

那麼淺度克隆的問題在哪了,接下來大家就會看到了
假如這時候又多了個妹子

var mary=user.clone();
mary.name='mary';
mary.gender='女';
mary.Tags.push('女神');

結果如下:
淺度克隆問題

問題顯而易見,圖中對象順序依次爲mary、jack、原對象,很明顯我們想要的效果其實是jack在Tags中是['標籤1','標籤2','男神'],mary的Tags是['標籤1','標籤2','女神'],而現狀是全部的Tags都變爲了['標籤1','標籤2','男神','女神'],原對象也是,而造成這個問題的原因就是數組是引用類型的= =…這個是基礎知識,我想大家都是知道的,所以簡單的賦值只是將數組地址賦給了新對象而已,真正引用和更改的仍然是原對象中的數組;

那麼解決方法已經很明顯了,判斷一下是否爲引用類型,將引用類型內的元素都賦值就好,利用遞歸函數就可以巧妙的解決,這就是深度克隆的原理了,下面上深度克隆demo:

Object.prototype.deepClone=function(){

    var newObj = this.constructor == Array?[]:{};//判斷克隆對象構造函數爲數組

    for(var key in this){
        if(this.hasOwnProperty(key)){
            if(typeof this[key] == "object"){
                newObj[key] = this[key].deepClone();
            }
            else{
                newObj[key] = this[key];
            }
        }
    }  
    //如果是構造函數的情況請加上,不然父深度克隆後的父鏈並不會指向原構造函數而是Object
    //  newObj.__proto__ = this.__proto__;
    return newObj;
};

var kalista = user.deepClone();
kalista.name='卡利斯塔';
kalista.gender='女';
kalista.Tags.push('LOL');
console.log(kalista);

var jugg=user.deepClone();
jugg.name='劍聖';
jugg.gender='男';
jugg.Tags.push('DOTA');
console.log(jugg);

結果如下:
深度克隆

完成~我寫的函數還是比較簡單的,我就不說明了,原理在上面也說過了,實現過程就跟原理所說的一樣,需要注意的只是數組的typeof爲object與記得遞歸後的賦值而已,over~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章