iT邦幫忙

2024 iThome 鐵人賽

DAY 28
1
JavaScript

從零開始學習JavaScript 30天系列 第 28

[Day 28] JavaScript 物件 淺拷貝、深拷貝(Copy)

  • 分享至 

  • xImage
  •  

Hi,大家好,我是Tony,是一個對於JavaScript有些概念的新手。

挑戰第28天!
今天的學習內容是:JavaScript 物件 淺拷貝、深拷貝(Copy)

學習內容來自
彭彭老師JavaScript 物件的淺拷貝、深拷貝
https://www.youtube.com/watch?v=tnT-XbrOKA0&list=PL-g0fdC5RMbqW54tWQPIVbhyl_Ky6a2VI&index=34

昨天的學習內容:[Day 27] JavaScript 代理物件基礎 (Proxy)
https://ithelp.ithome.com.tw/articles/10347669

1. 物件的拷貝/複製

物件的拷貝,講的就是物件的複製。
拷貝的部分包含物件與陣列,
陣列是一種比較特殊的物件。

那要如何要拷貝JavaScript的物件呢?
看下方狀況,

  1. 物件沒有被實際拷貝的狀況
    語法:
<script>
    let a={x:3,y:4};
    let b=a; //這裡沒有建立新的物件,只有參考到同一個物件
    b.x=5;
    console.log(a.x); //結果是印出5
</script>

因為是參考到同一個物件實體,所以利用b改變物件資料時,
印出a中的資料也會改變。

  1. 物件的拷貝
<script>
    let a={x:3,y:4};
    let b={...a}; //建立新的物件,並複製原物件的資料
    b.x=5;
    console.log(a.x); //結果是印出3
</script>

因為是有實際拷貝到原物件的資料,
所以在物件資料後來改變時,
也不影響拷貝的資料。

2. 什麼是 淺拷貝 (shallow Copy)

淺拷貝,就是只會拷貝物件的第一層資料
常見的拷貝工具都是淺拷貝
物件or陣列中會包含其他的物件or陣列,產生層次,
淺拷貝只會拷貝第一層,第二層以上的資料不會真的拷貝。
看下方範例,學習淺拷貝的方法

<script>
    let a={x:3,y:4,data:[1,2,3]}; //其中的data陣列就是第二層
    let b={...a}; //使用其餘運算符號...進行淺拷貝
    let c=Object.assign({},a); //使用內建方式Object.assign(),進行淺拷貝
</script>

3. 淺拷貝的特性

第二層以上的資料不會真的拷貝(不回完全複製一模一樣的內容),
會參考到原來相同的物件or陣列實體。
來看範例:

<script>
    let a={x:3,y:4,data:[1,2,3]}; //其中的data陣列就是第二層,沒有真正拷貝。
    let b={...a}; //a和b物件中的data是參考到同一個陣列實體。
    b.data[0]=4; //利用b操作data資料,也會影響a裡面的data。
    console.log(a.data[0]); //印出的結果是改變後的4。
</script>

4. 什麼是 深拷貝 (Deep Copy)

深拷貝就是完全拷貝物件底下所有層次的資料
全面性的把資料通通拷貝出來,就使用深拷貝。
方法有很多,今天學習的是簡便的方法。

  • 使用JSON.stringify(),將物件 字串化(Serialize)
  • 使用JSON.parse(),根據字串化的資料重新建構物件,完成深拷貝。

來看範例:

<script>
    let a={x:3,y:4,data:[1,2,3]};
    let str=JSON.stringify(a); //將物件結構字串化
    let b=JSON.parse(str); //根據字串化的資料,重新建立物件結構。   
</script>

5. 深拷貝的特性

深拷貝的特性就是拷貝出來的物件,與原本的物件,
兩者是完全獨立的物件實體。
操作範例:

<script>
    let a={x:3,y:4,data:[1,2,3]};
    let str=JSON.stringify(a);
    let b=JSON.parse(str);
    //以上完成深拷貝,a和b兩物件完全獨立互相不影響。
    
    b.data[0]=4; //b對data的操作不影響a的data
    console.log(a.data[0]); //印出原本陣列的資料1
</script>

6. 使用JSON方法深拷貝的限制

前面提到,要使用JSON方法深拷貝之前,
需要先有 字串化(Serialize)的動作,
所以最大的限制就是對無法字串化的資料,沒辦法使用。
像是函式、Symbol等資料,就是無法字串化。


練習

  • 練習1:淺拷貝,測試只有第一層的資料被拷貝
<script>
    let a=[0,1,{x:2,y:3}]; //有兩層的物件結構
    let b=[...a];  //進行淺拷貝,也可以使用Object.assign([],a);
    
    // 證明第一層的資料才能真正拷貝
    b[0]=10;
    console.log(a[0]); //第一層不會影響,印出0
    b[2].x=20;
    console.log(a[2].x); //第二層會影響,印出20
</script>

網頁結果1
成功印出結果0與20
https://ithelp.ithome.com.tw/upload/images/20240904/201684104qGMQSGhgq.jpg


  • 練習2:深拷貝,測試所以層次資料都會被拷貝
<script>
    let a=[0,1,{x:2,y:3}];
    let b=JSON.parse(JSON.stringify(a)); //字串化與重建物件結構寫在一起,完成深拷貝
    
    // 證明真正拷貝,兩個物件不會互相影響
    b[0]=10;
    console.log(a[0]); //第一層不會影響,印出0
    b[2].x=20;
    console.log(a[2].x); //第二層不會影響,印出2
</script>

網頁結果2
兩個物件不會互相影響,a印出來的都是原本的資料。
https://ithelp.ithome.com.tw/upload/images/20240904/20168410J08GoyPYEw.jpg

以上就是今天學習的內容,
挑戰快結束了,我還在思考後續的學習計劃,
那就先到這邊了,謝謝大家,明天見!


上一篇
[Day 27] JavaScript 代理物件基礎 (Proxy)
下一篇
[Day 29] JavaScript 實作練習- 製作碼表
系列文
從零開始學習JavaScript 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言