【JavaScript】淺層複製、深層複製

Neptune Li
Li-NInja
Published in
Nov 1, 2020

🚩 前言

物件在複製上與一般的屬性不一樣,
一般屬性在複製時是屬於 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

  1. 手動賦值
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. jQuery
let newPlayer = jQuery.extend({}, player);

4. ES6 語法
let linPlayer = Object.assign({}, player);

5. 展開運算子
let yinPlayer = {... player};

🚩 深層複製 Deep Copy

深層複製是第一層、第二層的值都可以 call by value
但是如果是物件裡面的物件的物件,
也就是包了三層的話依然還是會 call by reference

  1. jQuery

let tianPlayer = jQuery.extend(true, {}, player);

2. loadash
let dashPlayer = _.cloneDeep(player);

🚩 完全複製

如果要避免物件裡面有很多層的話,
最保險的做法就是將物件先轉成字串之後,
再把他轉成物件。

let str = JSON.stringify(player);
let piPokemon = JSON.parse(str);

但這個做法只適合用在純資料的地方,
如果物件裡面還包含有 functionmap ...等等的就會失效。

--

--