如果我想要複製物件的值,卻不希望在複製後,只要更動其值,原變數也會受到影響,該怎麼做呢?
本篇將介紹關於 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/