js 對(duì)象的深拷貝

我們使用=操作符復(fù)制對(duì)象時(shí),由于對(duì)象是通過(guò)引用傳遞的,父子對(duì)象引用的是內(nèi)存上同一個(gè)堆的地址,修改任意父子對(duì)象,父子對(duì)象都會(huì)改變,為了保證子對(duì)象修改不影響到父對(duì)象,需要進(jìn)行深拷貝

var arr = ['1','2'];
var obj = {
    name:'yy',
    age:['1','2'], 
    ojbs: {
        value: 1, 
        text: '中國(guó)'
    },
    arrs:[{
        value: 3, 
        text: '江西'      
    },{
        value: 4, 
        text: '廣東'      
    }]
};
obj.an = '1111';

數(shù)組深拷貝

var newArr = arr.slice(0);
var newArr2 = arr.concat();
newArr.push('4')
newArr2.push('4333')
console.log(newArr)
console.log(newArr2)

對(duì)象深拷貝

var deepCopyObj = function(obj ) { 
        var copy;
        
        // 處理3個(gè)簡(jiǎn)單的類型, null 或者 undefined
        if (obj === null || typeof obj !== 'object') {
            return obj;
        }

        if (obj instanceof Date) {
            copy = new Date();
            copy.setTime(obj.getTime());
            return copy;
        }

        if (obj instanceof Array) {
            var copy = [];
            for (var i = 0, len = obj.length; i < len; i++) {
                copy[i] = clone(obj[i]);
            }
            return copy;
        }

        if (obj instanceof Object) {
            var copy = {};
            for (var attr in obj) {
                if (obj.hasOwnProperty(attr)) {
                    copy[attr] = clone(obj[attr]);
                }
            }
            return copy;
        }

        throw new Error("Unable to copy obj! Its type isn't supported.");
}

console.time('deepCopyObj');  
var newObj = deepCopyObj(obj);
console.log(JSON.stringify(newObj))
console.timeEnd('deepCopyObj'); 

下面來(lái)總結(jié)一下實(shí)現(xiàn)深復(fù)制的的基本思路:
1.檢測(cè)當(dāng)前屬性是否為對(duì)象
2.因?yàn)閿?shù)組是特殊的對(duì)象,所以,在屬性為對(duì)象的前提下還需要檢測(cè)它是否為數(shù)組。
3.如果是數(shù)組,則創(chuàng)建一個(gè)[]空數(shù)組,否則,創(chuàng)建一個(gè){}空對(duì)象,并賦值給子對(duì)象的當(dāng)前屬性。然后,遞歸調(diào)用extendDeep函數(shù)。
上面例子使我們自己使用遞歸算法實(shí)現(xiàn)的一種深度復(fù)制方法。事實(shí)上,ES5新增的JSON對(duì)象提供的兩個(gè)方法也可以實(shí)現(xiàn)深度復(fù)制,
分別是JSON.stringify()和JSON.parse();前者用來(lái)將對(duì)象轉(zhuǎn)成字符串,后者則把字符串轉(zhuǎn)換成對(duì)象。下面我們使用該方法來(lái)實(shí)現(xiàn)一個(gè)深度復(fù)制的函數(shù):

根據(jù)不包含引用對(duì)象的普通數(shù)組深拷貝得到啟發(fā),不拷貝引用對(duì)象,拷貝一個(gè)字符串會(huì)新辟一個(gè)新的存儲(chǔ)地址,這樣就切斷了引用對(duì)象的指針聯(lián)系。

console.time('JSON');
var newObj1 = JSON.parse(JSON.stringify(obj))
console.log(JSON.stringify(newObj1))
console.timeEnd('JSON'); 

測(cè)試發(fā)現(xiàn),它也實(shí)現(xiàn)了深度復(fù)制。一般推薦使用后面這種方法,因?yàn)镴SON.parse和JSON.stringify是內(nèi)置函數(shù),處理起來(lái)會(huì)比較快。
另外,前面的那種方法使用了遞歸調(diào)用,我們都知道,遞歸是效率比較低的一種算法。

newObj.name = 'xx';
newObj.age.push('3');
newObj.ojbs.value = 3;
newObj.ojbs.code = '10001';
newObj.arrs.push({value: 5,text: '河北'   });

newObj1.arrs.push({value: 5,text: '河北'  });
newObj1.arrs.push({value: 6,text: '北京'  });

console.log(JSON.stringify(obj))
console.log(JSON.stringify(newObj))
console.log(JSON.stringify(newObj1))

上面的方法完全能夠Object、Array、Date、String、Number或者Boolean類型這6個(gè)簡(jiǎn)單類型的深拷貝,只要對(duì)象和數(shù)組中的數(shù)據(jù)形成一個(gè)樹(shù)狀結(jié)構(gòu),也就是說(shuō),在1個(gè)對(duì)象中沒(méi)有多于1個(gè)的對(duì)相同數(shù)據(jù)的引用。例如:

// 這是可以克隆的
var tree = {
    "left": { "left": null, "right": null, "data": 3 },
    "right": null,
    "data": 8
};

// 這樣也可以工作,但是你會(huì)得到2份內(nèi)部節(jié)點(diǎn),而不是2個(gè)引用相同的副本
var directedAcyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};

directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

var newdirectedAcyclicGraph = clone(directedAcyclicGraph)
newdirectedAcyclicGraph.data = 9;
console.log(JSON.stringify(directedAcyclicGraph))
console.log(JSON.stringify(newdirectedAcyclicGraph))      

// 這種情況因?yàn)闊o(wú)限的遞歸,會(huì)導(dǎo)致堆棧溢出
//"Uncaught RangeError: Maximum call stack size exceeded"
var cylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cylicGraph["right"] = cylicGraph;

var newcylicGraph = deepCopyObj(cylicGraph)
newcylicGraph.data = 9;
console.log(JSON.stringify(cylicGraph))
console.log(JSON.stringify(newcylicGraph))

這個(gè)clone的方法不能處理所有的JS對(duì)象,但已經(jīng)能滿足大部分的需求了,只要你不把所有的工作的丟給它就可以了。

作者:mervynYang
鏈接:http://www.itdecent.cn/p/37f39715c2f8
來(lái)源:簡(jiǎn)書(shū)
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容