前言
淺層複製及深層複製又有人會稱作淺拷貝以及深拷貝,是怎麼定義的呢?
有的時候我們會希望用另一個變數,複製相同結構的物件,但我們又不希望他們指向的是同一個記憶體空間,
除了之前提到的用物件實字的方式宣告之外,還有沒有其他的辦法呢?
這裡提供兩種辦法,就是所謂的淺拷貝以及深拷貝
淺層複製(淺拷貝-Shallow Copy)
淺拷貝指的就是沒有辦法每一層的物件都完全脫鉤,包含三種方法:
1. for-in loop
var family = {
name: '小明家',
members: {
father: '老爸',
mom: '老媽',
ming: '小明'
}
};
var family2 = {};
for(key in family) {
console.log(key); // family 物件第一層有幾個屬性就跑幾次
family2[key] = family[key];
}
console.log(family, family2);
console.log(family == family2); // false
這邊的 key 不一定要叫做 key,你可以任意取名字,當 for-in 迴圈用在物件的時候,則會依照該物件的 第一層屬性有幾個就跑幾次,以 family 的物件來說,第一層有 name 以及 members 兩個屬性,所以跑兩次,而 key 就會是屬性的名稱,所以跑第一次的時候 key 是 name ,第二次的時候 key 是 members
所以在依照這樣的模式將值塞入 family2 之後,就完成淺拷貝。
印出來以後可以看到兩個物件的內容都相同,但 family == family2 的結果為false ,因此就算修改 family2 的內容,也不會對 family 造成影響。
不過,淺層複製並不會在所有的情境中都能免除上述的困擾,物件第二層以下,仍舊是用傳參考的方式傳入的。
如果我今天改動 family2.members.ming = '大明'; 的時候,family.members.ming 也會跟著改動喔,因為他們兩個物件中的子物件都還是指向同一個記憶體位置的狀態。
所以這就是淺拷貝的特點,雖然第一層是分開的,但第二層之後卻還是有可能造成 call by reference 的狀況
所以反之,深拷貝就是連物件中的子物件都會指向不同的記憶體空間,並且保持內容結構都一模一樣。
2. jQuery extend
var family = {
name: '小明家',
members: {
father: '老爸',
mom: '老媽',
ming: '小明'
}
};
// jQuery extend
var family3 = jQuery.extend({}, family);
console.log(family, family3);
3. ES6 Object.assign
var family = {
name: '小明家',
members: {
father: '老爸',
mom: '老媽',
ming: '小明'
}
};
// ES6 Object.assign
var family4 = Object.assign({}, family);
console.log(family, family4);
深層複製(深拷貝-Deep Copy)
深層複製就是先把物件變成字串,再轉回物件,將傳參考的特性完全消滅。
相當於建立一個新的參考位置,一個完全獨立於原物件的新物件。
var family = {
name: '小明家',
members: {
father: '老爸',
mom: '老媽',
ming: '小明'
}
};
console.log(JSON.stringify(family));
console.log(JSON.parse(JSON.stringify(family)));
首先透過 JSON.stringify 將 family 轉成純字串
再透過 JSON.parse 將字串轉回物件
這個時候,無論我們怎麼對 deepFamily 做修改,都影響不到 family
var deepFamily = JSON.parse(JSON.stringify(family));
deepFamily.name = '杰倫家';
deepFamily.members.ming = '大明';
console.log(family , deepFamily);