JS中如何實現(xiàn)一個深拷貝

淺拷貝只復(fù)制指向某個對象的引用嗜逻,而不復(fù)制對象本身,新舊對象還是共享同一塊內(nèi)存缭召;但深拷貝會另外創(chuàng)造一個一模一樣的對象栈顷,新對象跟原對象不共享內(nèi)存,它們是完全隔離嵌巷,互不影響的萄凤,對一個對象的修改并不會影響另一個對象。
區(qū)別:淺拷貝只復(fù)制對象的第一層屬性搪哪,深拷貝可以對對象的屬性進行遞歸復(fù)制靡努,直至屬性值為基本類型;
那么如何實現(xiàn)一個深拷貝呢晓折?
下面這段代碼通過遞歸復(fù)制惑朦,實現(xiàn)了一個初步的深拷貝函數(shù),但是并不完善漓概,具體見代碼行嗤。

 // 1-簡單版
    // 不足:(1)拷貝后的復(fù)雜數(shù)據(jù)類型只有對象和數(shù)組兩種
    // (2)對于引用自身的屬性直接跳過
    // (3)無法拷貝特殊類型 Date 、RegExp
    function deepCopy(obj1) {
        const obj2 = Array.isArray(obj1) ? [] : {};
        if (obj1 && typeof obj1 === "object") {
            for (let i in obj1) {
                let prop = obj1[i]; // 避免相互引用造成死循環(huán)垛耳,如obj1.a=obj1
                if (prop === obj1) {
                    continue;
                }
                // 僅拷貝對象自身屬性
                if (obj1.hasOwnProperty(i)) {
                    // 如果子屬性為引用數(shù)據(jù)類型,遞歸復(fù)制
                    if (prop && typeof prop === "object") {
                        obj2[i] = deepCopy(prop);
                    } else {
                        // 如果是基本數(shù)據(jù)類型,只是簡單的復(fù)制
                        obj2[i] = prop;
                    }
                }
            }
        }
        return obj2;
    }

改進后的深拷貝函數(shù)如下:

 //2-升級版
    // 可處理特殊類型 Date 堂鲜、RegExp
    // 可處理存在循環(huán)引用的對象栈雳,如 obj.a=obj
    // 不足:無法深拷貝對象的函數(shù)屬性(可用eval處理箭頭函數(shù),但處理不了一般函數(shù)缔莲,以下代碼沒實現(xiàn))
    // 實際中哥纫,可以用 lodash 庫提供的 cloneDeep 來實現(xiàn)深拷貝,不過它也未實現(xiàn)對函數(shù)深拷貝痴奏,
    // An empty object is returned for uncloneable values such as error objects, functions, DOM nodes, and WeakMaps.
    // https://github.com/lodash/lodash/blob/master/.internal/baseClone.js
    function deepCopy2(obj,weakmap=new WeakMap()) {
        if(weakmap.has(obj)){ return weakmap.get(obj)}
        if(obj===null){ return null;}
        if(obj instanceof RegExp){
            return new RegExp(obj);
        }
        if(obj instanceof Date){
            return new Date(obj);
        }
        //基本數(shù)據(jù)類型或者函數(shù)蛀骇,直接返回
        //這樣處理函數(shù)就不是深拷貝了
        const type=typeof obj;
        if(type !=='object'){
            return obj;
        }
        /**
         * 如果obj是數(shù)組,那么 obj.constructor 是 [Function: Array]
         * 如果obj是對象读拆,那么 obj.constructor 是 [Function: Object]
         */
         let cons=obj.constructor;
         let res=new obj.constructor();
        // 當對象的一個屬性引用自身時擅憔,要避免相互引用造成死循環(huán),如obj1.a=obj1
        // 可使用 WeakMap 來存儲這個引用自身的屬性
         weakmap.set(obj,res);

         // 拷貝對象上的可遍歷屬性
         for(let key in obj){
             res[key]=deepCopy2(obj[key],weakmap);
         }
         return res;
    }

改進后的深拷貝函數(shù)基本上可以滿足使用要求檐晕。注意其中幾點:
(1)借助一個 WeakMap 結(jié)構(gòu) weakmap暑诸,存儲已復(fù)制的對象,這樣在復(fù)制引用自身的屬性時辟灰,直接返回 weakmap 中已有的對象个榕,從而避免陷入死循環(huán)。(深拷貝存在遞歸復(fù)制芥喇,存在函數(shù)嵌套西采,所以使用 WeakMap 而不是 Map —— WeakMap 的鍵名所指向的對象,不計入垃圾回收機制继控。)
(2)特殊類型 Date 械馆、RegExp,如果直接通過以下兩行代碼復(fù)制湿诊, Date類型屬性值是代碼執(zhí)行時的時間狱杰,而不是原始對象對應(yīng)屬性值;對于 RegExp類型屬性值厅须,結(jié)果就是根本不符仿畸。所以對這兩類特殊類型值,需要做特殊處理朗和。

         let cons=obj.constructor;
         let res=new obj.constructor();

(3)通過上面這兩行代碼错沽,保證拷貝后的對象類型與原始對象類型保持一致。
(4)諸如 error objects, functions, DOM nodes, and WeakMaps 這些值眶拉,是不可拷貝的千埃。

最后,關(guān)于深淺拷貝的詳細介紹忆植,可看這篇文章放可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谒臼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子耀里,更是在濱河造成了極大的恐慌蜈缤,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冯挎,死亡現(xiàn)場離奇詭異底哥,居然都是意外死亡,警方通過查閱死者的電腦和手機房官,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門趾徽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人翰守,你說我怎么就攤上這事孵奶。” “怎么了潦俺?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵拒课,是天一觀的道長。 經(jīng)常有香客問我事示,道長早像,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任肖爵,我火速辦了婚禮卢鹦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘劝堪。我一直安慰自己冀自,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布秒啦。 她就那樣靜靜地躺著熬粗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪余境。 梳的紋絲不亂的頭發(fā)上驻呐,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音芳来,去河邊找鬼含末。 笑死,一個胖子當著我的面吹牛即舌,可吹牛的內(nèi)容都是我干的佣盒。 我是一名探鬼主播顽聂,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼盯仪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了磨总?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤笼沥,失蹤者是張志新(化名)和其女友劉穎娶牌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體诗良,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年鉴裹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片径荔。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出待德,到底是詐尸還是另有隱情,我是刑警寧澤鹦马,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站荸频,受9級特大地震影響菱肖,放射性物質(zhì)發(fā)生泄漏旭从。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一遇绞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摹闽,春花似錦蹄咖、人聲如沸付鹿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至俊抵,卻和暖如春谁不,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背徽诲。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工刹帕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谎替。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓偷溺,卻偏偏與公主長得像,于是被迫代替她去往敵國和親钱贯。 傳聞我的和親對象是個殘疾皇子挫掏,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容