如果我想要複製物件的值,卻不希望在複製後,只要更動其值,原變數也會受到影響,該怎麼做呢?
本篇將介紹關於 JavaScript 中的「淺拷貝」以及「深拷貝」。
原始型別在賦值時一般是直接傳值的方式(pass by value):
1 2 3 4 5 6
| let a= 1; let b = a; b = 2;
console.log(a); console.log(b);
|
但是物件會是傳指標(pass by Reference):
1 2 3 4 5 6
| let obj1 = { a:1, b:2, c:3}; let obj2 = obj1; obj2.b = 4 console.log(obj1) console.log(obj2)
|
淺拷貝 Shallow Copy
原本 a
和 b
是指向同一塊記憶體位址;透過重新賦值的方式,讓 b
指向一個新的記憶體位址:
1 2 3 4 5 6 7 8 9
| var a = {name: 'William'}
var b = a;
b = {name: "Teddy"};
console.log(a.name);
console.log(b.name);
|
同樣的範例還有這個,我們直接把 a 取出的值放到屬性名稱後面:
1 2 3 4 5 6 7 8 9 10
| var a = {name: 'William', age: 70};
var b = {name: a.name, age: a.age};
b.name = "Teddy";
console.log(a.name);
console.log(b.name);
|
也可以使用 Object.assign 的方式來複製:
1 2 3 4 5
| var a = {name: 'William', age: 70}; var b = Object.assign({}, a); b.name = "Teddy"; console.log(a.name); console.log(b.name);
|
但是以上使用淺拷貝只能複製一層。
當拷貝到第二層的時候就會發生問題:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| var obj = {
a: 1,
b: {
b1: 2,
b2: 3
} }; var obj2 = Object.assign({}, obj);
obj2.a= 10;
obj2.b.b1= 20;
console.log(obj.a);
console.log(obj.b.b1);
|
物件 obj2
改變 a
並不會影響物件 obj
的 a
,但是改變再深一層的物件的值,就會影響到原本 a
的 b.b1
了!
讓我們在看一個例子:
1 2 3 4 5 6 7 8
| let obj1 = {a:{b:5}}; let obj2 = {a:obj1.a}; obj2.a.b = 10 console.log(obj1) console.log(obj2) console.log(obj1 === obj2) console.log(obj1.a === obj2.a)
|
當我們要確保物件是整個複製,而不是只複製 reference 時就需要用到 Deep Copy 。
深拷貝 Deep Copy
JSON.parse(JSON.stringify(object_array)):
- JSON.parse():把字串轉成物件
- JSON.stringify():把物件轉成字串。
我們可以把物件先轉換成 JSON 再 parse 回來
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var obj = { a: 1, b: { b1: 2, b2: 3 } };
var obj2 = JSON.parse(JSON.stringify(obj));
obj2.a= 10; obj2.b.b1= 20;
console.log(obj.a); console.log(obj.b.b1);
|
也可以透過使用第三方套件(ex: JQuery、lodash)的方式:
Lodash
1 2 3 4 5 6 7 8 9
| var obj = { a: 1, b: { b1: 2, b2: 3 } };
var obj2 = cloneDeep(obj);
|
Jquery
深拷貝和淺拷貝對應的參數是 true 或 false 。
預設情況是 false(淺拷貝),而且 false 不能夠寫出來,也就是你想要淺拷貝,那就什麼參數都不用帶。如果想帶入參數,只能傳入 true(深拷貝)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var obj = {}; var obj2 = { a: 1, b: { b1: 2, b2: 3 } };
$.extend(true, obj, obj2);
obj.b.b1= 20;
console.log(obj2.b.b1);
$.extend(obj,obj2);
|
參考文獻
https://ithelp.ithome.com.tw/articles/10200860
https://dustinhsiao21.com/2018/01/07/javascript-shallow-copy-and-deep-copy/