????????先考慮一種情況,對一個已知對象進(jìn)行拷貝,編譯系統(tǒng)會自動調(diào)用一種構(gòu)造函數(shù)——拷貝構(gòu)造函數(shù),如果用戶未定義拷貝構(gòu)造函數(shù),則會調(diào)用默認(rèn)拷貝構(gòu)造函數(shù)。
執(zhí)行結(jié)果:調(diào)用一次構(gòu)造函數(shù),調(diào)用兩次析構(gòu)函數(shù),兩個對象的指針成員所指內(nèi)存相同,name指針被分配一次內(nèi)存,但是程序結(jié)束時該內(nèi)存卻被釋放了兩次,會造成內(nèi)存泄漏問題!
這是由于編譯系統(tǒng)在我們沒有自己定義拷貝構(gòu)造函數(shù)時,會在拷貝對象時調(diào)用默認(rèn)拷貝構(gòu)造函數(shù),進(jìn)行的是淺拷貝!即對指針name拷貝后會出現(xiàn)兩個指針指向同一個內(nèi)存空間。
所以,在對含有指針成員的對象進(jìn)行拷貝時,必須要自己定義拷貝構(gòu)造函數(shù),使拷貝后的對象指針成員有自己的內(nèi)存空間,即進(jìn)行深拷貝,這樣就避免了內(nèi)存泄漏發(fā)生。
執(zhí)行結(jié)果:調(diào)用一次構(gòu)造函數(shù),一次自定義拷貝構(gòu)造函數(shù),兩次析構(gòu)函數(shù)。兩個對象的指針成員所指內(nèi)存不同。
總結(jié):淺拷貝只是對指針的拷貝,拷貝后兩個指針指向同一個內(nèi)存空間,深拷貝不但對指針進(jìn)行拷貝,而且對指針指向的內(nèi)容進(jìn)行拷貝,經(jīng)深拷貝后的指針是指向兩個不同地址的指針。
深拷貝方法:
? ? ? ? ? ?1. 使用JSON.parse()與JSON.stringify()對對象進(jìn)行拷貝
????????????????通常情況下,我們可以使用JSON.parse()與 JSON.stringify()實現(xiàn)對象的深克隆,如下:
????????????????var clone = function (obj) {
? ? ????????????return JSON.parse(JSON.stringify(obj));
????????????????}? ? ? ? //這種方法只適用于純數(shù)據(jù)json對象的深度克隆,因為有些時候,這種方法也有缺陷
? ? ? ? ? ? 2.目前沒有發(fā)現(xiàn)bug的對象深拷貝方法
? ? ? ? ? ? ?var clone = function (obj) {
? ????????????????? if(obj === null) return null
? ????????????????? if(typeof obj !== 'object') return obj;
? ????????????????? if(obj.constructor===Date) return new Date(obj);
????????? ????????? if(obj.constructor === RegExp) return new RegExp(obj);
? ? ? ? ? ? ? ? ? ? ?var newObj = new obj.constructor ();? //保持繼承鏈
? ????????????????? for (var key in obj) {
? ? ????????? ????????????? if (obj.hasOwnProperty(key)) {? //不遍歷其原型鏈上的屬性
? ? ????????????????? ? ? ? var val = obj[key];
? ? ? ????????????????? ? ? newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除與函數(shù)名的耦合
? ? ? ? ? ????????????? ? ?}
????????????? ? }?
? ????????????? return newObj;?
????????};
3.展開運算符進(jìn)行淺拷貝
? ? ? ? var arr1=[1,2,5,6,4];
? ? ? ? var arr2=[...arr1];
? ? ? ? arr1 == arr2? ? ? // false;