0%

JS 核心觀念筆記 - 物件的淺層複製與深層複製

core

先前有提到物件的特性是傳參考,但因為這個特性也會導致一些資料處理上的困擾,物件中有淺層複製跟深層複製的方法,來處理這個困擾。

原始物件資料

1
2
3
4
5
6
7
8
var family = {
home: "提姆家",
members: {
dad: "Tim",
mom: "Min",
son: "Joshua",
},
};

淺層複製

for…in

使用 for...in 的方法取得物件資料,並可以得到以下的值。

1
2
3
4
5
var newFamily = {};
for (const key in family) {
console.log(key);
console.log(family[key]);
}
  • key: 會取到 family 物件的第一層的屬性,也就是 homemembers
  • family[key]: 會取到 home 的值跟 members 的值(members 是物件)。

淺拷貝

讓新的物件裡面的值等於原本物件裡面的值。

1
2
3
4
5
6
var newFamily = {};
for (const key in family) {
newFamily[key] = family[key];
console.log((newFamily[key] = family[key]));
console.log(newFamily[key] === family[key]); //true
}

這時候再比對一下兩個物件,會得到 false,代表 newFamily 已經是新的物件了。

1
2
3
4
5
var newFamily = {};
for (const key in family) {
newFamily[key] = family[key];
}
console.log(family === newFamily); //false

這時把新物件的 home 修改成別的值,並且看一下兩個物件的內容。

1
2
3
4
5
6
7
var newFamily = {};
for (const key in family) {
newFamily[key] = family[key];
}
newFamily.home = "約約家";
console.log(family);
console.log(newFamily);

會發現 newFamily 第一層的 home 屬性被修改了,但 family 沒有,因為這兩個物件已經沒有關係了。
.
.
.
BUT! 人生最重要就是這個 BUT 了!
.
.
.
如果把 newFamily 裡面的 members 中的屬性改掉,

1
2
3
4
5
6
7
8
9
var newFamily = {};
for (const key in family) {
newFamily[key] = family[key];
}
newFamily.home = "約約家";

newFamily.members.dad = "提姆爸爸";
console.log(family);
console.log(newFamily);

會看到 members 裡面的 dad 還是被改掉了,

淺複製

原因是透過這樣的方式只能改變第一層的屬性內容,第二層資料內容還是以傳參考的形式,這個方式就叫做淺層複製,也有稱為淺拷貝。

其他方式寫法

jQuery 的寫法

使用 jQuery 的 extend 方法,前面先帶一個空物件,後面放入要複製的物件實字。

1
var newFamily2 = jQuery.extend({}, family);

ES6 的寫法

使用 ES6 寫法,使用 Object 的 assign 方法,前面帶一個空物件,後面放入要複製的物件實字。

1
var newFamily3 = Object.assign({}, family);

深層複製

為了不要有物件傳參考的特性,會先把資料轉型成字串,再轉型成物件,

先轉成字串

1
2
console.log(family); //原本的物件
console.log(JSON.stringify(family)); //把物件轉成字串

深拷貝

再轉成物件

再使用 JSON.parse 轉型成物件,這時候新的物件就跟原本的 family 物件沒有關聯了。

1
console.log(JSON.parse(JSON.stringify(family)));

深拷貝2

兩者物件已無相聯性

將轉型後的物件賦予在新的變數上,並做比對,會發現是 false

1
2
let newFamily4 = JSON.parse(JSON.stringify(family));
console.log(family === newFamily4); //false