跳至內容
Astera Technology

複製了物件,內層為何仍一起變?

外層已複製,仍要找出共用的內層物件。

下載完整個案資料及參考答案 ↓

先追這段程式

用展開語法複製草稿,再改副本的 title 和 style.ink。哪一項會牽動原件?

完整原始程式
const original={title:'Draft',style:{ink:'green'}};
const copy={...original};copy.style.ink='purple';copy.title='Copy';
console.log(JSON.stringify({original,copy,sameStyle:original.style===copy.style}));
確實的 console 輸出
{"original":{"title":"Draft","style":{"ink":"purple"}},"copy":{"title":"Copy","style":{"ink":"purple"}},"sameStyle":true}
值與執行位置
欄位或參照改動後原件改動後副本
titleDraftCopy
style.inkpurplepurple
style identity與副本共用sameStyle: true

結果為何如此

展開語法把自有、可列舉屬性的值放到新外層物件。title 是文字值,style 卻是物件參照,兩份資料仍指向同一 style。修改前要另複製這一支;以下修正並非萬用深層複製。

比較另一種寫法

有新外層物件,並不保證內層原值保留。以下重新用綠色原件,同時複製 style;沒有改的 meta 支仍然共用。

另開的有限例子
const original={title:'Draft',style:{ink:'green'},meta:{size:4}};
const copy={...original,style:{...original.style,ink:'purple'}};copy.title='Copy';
console.log(JSON.stringify({originalInk:original.style.ink,copyInk:copy.style.ink,sameStyle:original.style===copy.style,sameMeta:original.meta===copy.meta}));
另一寫法的輸出
{"originalInk":"green","copyInk":"purple","sameStyle":false,"sameMeta":true}

試清邊界

只想改副本的 style.ink,複製應做到哪一層?

查看參考答案

外層 note 和 style 都要新建,再在該支設定 ink。其他內層若也要改,需逐支決定怎樣複製。

重新建立的邊界例子
const original={style:{ink:'green'}};const copy={...original};copy.extra=1;
console.log(JSON.stringify({sourceHasExtra:Object.hasOwn(original,'extra'),copyHasExtra:Object.hasOwn(copy,'extra'),sameStyle:original.style===copy.style}));
邊界例子的輸出
{"sourceHasExtra":false,"copyHasExtra":true,"sameStyle":true}

原始例子檔案

相關資源