js對象深拷貝淺拷貝
對象的深拷貝於淺拷貝
對於基本類型,淺拷貝過程就是對值的復制,這個過程會開辟出一個新的內存空間,將值復制到新的內存空間。而對於引用類型來書,淺拷貝過程就是對指針的復制,這個過程並沒有開辟新的堆內存空間,只是將指向該內存的地址進行了復制。然而對引用類型的淺拷貝會出現一個問題,那就是修改其中一個對象的屬性,則另一個對象的屬性也會改變。產生了問題那必然有相對解決的方法, 就這樣深拷貝就開始入場了,深拷貝會開辟新的棧,兩個對象對應兩個不同的地址,這樣一來,改一個對象的屬性,也不會改變另一個對象的屬性。
下面我們用代碼看一下深拷貝於淺拷貝是如何實現的 :
對象的淺拷貝
對象的淺拷貝實現方法很簡單,說白了就是一個for in 循環的事情 :
let obj = {
nNum : 1,
sName : 'aaron'
};
function shallowCopy(args) {
let result = {};
for(let item in args) {
if(args.hasOwnProperty(item)) {
result[item] = args[item];
};
};
return result;
};
shallowCopy(obj);
或者,我們可以使用最常見的jQuery來實現這個功能 :
$.extend({} , obj);
亦或者,我們也可以采用ES6的方法用一行代碼實現相同的功能 :
Object.assign({} , obj);
對於淺拷貝就說到這了,如果有補充或者發現問題的大牛可以回復我或者郵件通知,我會第一時間進行回復,好了廢話說多了,我們接下來看一下深拷貝
對象的深拷貝
如果我們把上面的obj稍微修改一下那淺拷貝就有心無力了 :
let obj = {
nNum : 1,
oAar : [1,2,3,4]
};
我們不妨可以再用上面的方法試一下
let newObj = shallowCopy(obj); newObj === obj // false newObj.oAar === obj.oAar // true
從上面的結果顯示我們可以看出,newObj.oAar與obj.oAar指針所指的是同一個位置,那我們如何改正這個問題呢?
其實也很容易,我們將obj.oAar再看待為一個新的對象,對其再進行一次淺拷貝不就可以了嗎??不說了,上代碼
function deepCopy(args) {
let result = {};
for(let item in args){
if(typeof args[item] === 'object' && args[item] !== null){
result[item] = deepCopy(args[item]);
}else{
result[item] = args[item];
};
};
return result;
};
result(obj);
我們來驗證一下
let newObj = result(obj);
newObj === obj // false
newObj.oAar === obj.oAar // false
結果也顯示我們實現了,ok
但是有沒有其他的方式呢,比如說更簡潔一些的,也是有的:
我們可以使用jQuery的$.extend(true, {}, obj)
,同樣也可以實現,是不是覺得眼熟。前面我們說淺拷貝的時候也說過這個方法,但是多了一個為true的參數,$.extend()
方法,第一個參數默認為false,當設置它為true時則會開啟深拷貝模式。
想想還有沒有什麽其他的方式= ̄ω ̄=?
其實還有一個捷徑可走
還是上面舉的那個obj,我們對它再進行一次嘗試
let obj = {
nNum : 1,
oAar : [1,2,3,4]
};
function deepCopy(args) {
let result = {};
try {
result = JSON.parse(JSON.stringify(args));
}
return result;
}
let newObj = deepCopy(obj);
newObj === obj // false
newObj.oAar === obj.oAar // false
ヾ(?`Д′?) 什麽鬼,這樣也行? 那還前面說那麽多廢話,直接上這個方法豈不是爽歪歪?
但是這裏不得不說明一點,投機取巧往往能達到看似相同的結果,但是還是存在一些隱性的問題的
就如上面這種方式和遞歸的方法相比是有弊端的,比如它會拋棄對象的constructor。也就是深拷貝之後,不管這個對象原來的構造函數是什麽,在深拷貝之後都會變成Object。
這種方法能正確處理的對象只有 Number, String, Boolean, Array, 扁平對象,即那些能夠被 json 直接表示的數據結構。RegExp對象是無法通過這種方式深拷貝。
最後再說一種方法,可以使用Object.create()方法達到深拷貝的效果
function deepCopy(args) {
let result = {};
for(let item in args){
if(typeof args[item] === 'object' && args[item] !== null){
result[item] = args[item].constructor === Array ? [] :
Object.create(prop);
}else{
result[item] = args[item];
};
};
return result;
}
let newObj = deepCopy(obj);
newObj === obj // false
newObj.oAar === obj.oAar // false
好了,更多的第三方庫的方法我們就不一一列舉了,原理更重要嘛,對吧。
最後我們來總結一下:
淺拷貝我們說了3種方法 :
- 通過for...in循環來實現
- 通過Object.assign()方法來實現
- 通過jQuery中的$.extend()方法來實現
深拷貝我們同樣說了四種方法 :
- 通過遞歸的手法實現
- 通過jQuery中的$.extend()添加true參數方法來實現
- 通過JSON序列化反序列化來實現
- 用過Object.create()方法來實現
除了這幾種如果各位還想到了其他什麽好的方法歡迎下方留言ヾ( ̄▽ ̄)
js對象深拷貝淺拷貝