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
物件的拷貝,講的就是物件的複製。
拷貝的部分包含物件與陣列,
陣列是一種比較特殊的物件。
那要如何要拷貝JavaScript的物件呢?
看下方狀況,
<script>
let a={x:3,y:4};
let b=a; //這裡沒有建立新的物件,只有參考到同一個物件
b.x=5;
console.log(a.x); //結果是印出5
</script>
因為是參考到同一個物件實體,所以利用b改變物件資料時,
印出a中的資料也會改變。
<script>
let a={x:3,y:4};
let b={...a}; //建立新的物件,並複製原物件的資料
b.x=5;
console.log(a.x); //結果是印出3
</script>
因為是有實際拷貝到原物件的資料,
所以在物件資料後來改變時,
也不影響拷貝的資料。
淺拷貝,就是只會拷貝物件的第一層資料。
常見的拷貝工具都是淺拷貝
物件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>
第二層以上的資料不會真的拷貝(不回完全複製一模一樣的內容),
會參考到原來相同的物件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>
深拷貝就是完全拷貝物件底下所有層次的資料
全面性的把資料通通拷貝出來,就使用深拷貝。
方法有很多,今天學習的是簡便的方法。
來看範例:
<script>
let a={x:3,y:4,data:[1,2,3]};
let str=JSON.stringify(a); //將物件結構字串化
let b=JSON.parse(str); //根據字串化的資料,重新建立物件結構。
</script>
深拷貝的特性就是拷貝出來的物件,與原本的物件,
兩者是完全獨立的物件實體。
操作範例:
<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>
前面提到,要使用JSON方法深拷貝之前,
需要先有 字串化(Serialize)的動作,
所以最大的限制就是對無法字串化的資料,沒辦法使用。
像是函式、Symbol等資料,就是無法字串化。
<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
<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印出來的都是原本的資料。
以上就是今天學習的內容,
挑戰快結束了,我還在思考後續的學習計劃,
那就先到這邊了,謝謝大家,明天見!