【JavaScript】淺層複製、深層複製
🚩 前言
物件在複製上與一般的屬性不一樣,
一般屬性在複製時是屬於 call by value
,
而物件再複製時是屬於 call by reference
。
兩個的結果就會大不相同。
call by value
// call by value
let myPokemon = '皮卡丘';
let jayPokemon = myPokemon;
jayPokemon = '雷丘';
console.log(myPokemon); //皮卡丘
call by reference
let myPokemon = {
name: '皮卡丘',
type: '電',
}
let jayPokemon = myPokemon;
jayPokemon.name = '雷丘';
console.log(a.name); //雷丘
在 call by reference
中,
物件的複製其實是複製了一段記憶體位置,
所以在範例中 jayPokemon
所指向的記憶體位置是與 myPokemon
一樣的,
因此改變 jayPokemon
就等於改變 myPokemon
。
想要解決的話可以使用淺層複製 (Shallow Copy)
或是深層複製(Deep Copy) 來解決。
接下來會以範例程式碼來介紹兩者差異。
let player = {
name: '小智',
ages: 10,
birthplace: '真心鎮',
firstPokemon: {
name: '夢幻',
type: '超能力',
level: 99
}
};
🚩 淺層複製 Shallow Copy
淺層複製是第一層的值都可以 call by value
,
但是如果是物件裡面的物件 firtsPokemon
依然還是會 call by reference
。
- 手動賦值
let jayPlayer = {
name: player.name,
ages: player.ages,
birthplace: player.birthplace,
firstPokemon: player.firstPokemon
};
2. for…in
let kaiPlayer = {};
for (var item in player) {
kaiPlayer[item] = player[item];
}
3. jQuerylet newPlayer = jQuery.extend({}, player);
4. ES6 語法let linPlayer = Object.assign({}, player);
5. 展開運算子let yinPlayer = {... player};
🚩 深層複製 Deep Copy
深層複製是第一層、第二層的值都可以 call by value
,
但是如果是物件裡面的物件的物件,
也就是包了三層的話依然還是會 call by reference
。
- jQuery
let tianPlayer = jQuery.extend(true, {}, player);
2. loadashlet dashPlayer = _.cloneDeep(player);
🚩 完全複製
如果要避免物件裡面有很多層的話,
最保險的做法就是將物件先轉成字串之後,
再把他轉成物件。
let str = JSON.stringify(player);
let piPokemon = JSON.parse(str);
但這個做法只適合用在純資料的地方,
如果物件裡面還包含有 function
、 map
...等等的就會失效。