情境:傳遞Object給dialog,在dialog中透過雙向綁定傳入的Object,在dialog中變更Object,因為在JavaScript中,Object的傳遞是call by reference,所以外部的Object也會一起被連動,有沒有辦法可以不讓Object被連動呢?
父層component.ts
Dialog component.ts
this.componentItem = this.config.data.componentItem;
Dialog .html
<ec-language-tab-panel [hasJP]="true" [(ngModel)]="componentItem.title['s']"></ec-language-tab-panel>
分析
在分析之前要先有JavaScript的基本認識,JavaScript中傳遞值的方式有兩種
- Pass by value,傳遞的值型態為Primitive type,只傳value,參數間不會互相影響
- Pass by reference,傳遞的值型態為Object,這個狀態下傳遞參數會被指向記憶體位址,參數會互相連動
解決方案
- 將傳入的參數全部攤平,變成pass by value,但這個做法不是很簡潔,所以沒採用
- 建立一個新物件並傳入原本物件的值,而不是址,避免連動
- 淺拷貝(shallow copy)
將原始物件的屬性複製到新物件中,但其內部的屬性仍然是原始物件的引用,意思是Object中的屬性必須要是Primitive Type,如果有屬性還是Object的話還是會跟原始的Object連動,所以才叫淺拷貝const copiedObject = Object.assign({}, originalObject);
- 深拷貝(deep copy)
將物件透過JSON.stringify轉成JSON字串,再將JSON字串轉成物件,也可以使用lodash 的 cloneDeep來達到,但需要額外引入libraryconst copiedObject = JSON.parse(JSON.stringify(this.config.data.componentItem));
- 淺拷貝(shallow copy)
:::success
深拷貝works
:::
:::danger
淺拷貝因為這次操作的Object剛好是兩層的Object結構,所以沒作用
:::
效能
深拷貝效能較不好的原因
- 深拷貝會創建一個新的物件
- JSON.parse(JSON.stringify())執行的效能不是很理想
關於效能上的比對可以參考Stackoverflow上的這篇,裡面有對比
參考資料