淺談 js 深拷貝與淺拷貝的差異

Deep copy 和 Shallow copy


先來個考題:

a = { foo: "bar" };
b = a;
b.foo = "baz";

console.log(a.foo); // 印出?
答案
baz



下一題:

a = { foo: "bar" };
b = structuredClone(a); // 深拷貝
b.foo = "baz";

console.log(a.foo); // 印出?
答案
bar

深拷貝(Deep Copy) 可以將內層對象一併拷貝





Shallow copy


淺拷貝(Shallow Copy) 與深拷貝同樣是用來拷貝物件層級,避免指向同一記憶體位置

與深拷貝不同的是,淺拷貝只會複製第一層的對象,如果是 Object.Object 的結構就沒轍。


Object.assign


Object.assign 屬於淺拷貝(Shallow Copy)
在上述案例中,可以得到跟深拷貝一樣的結果

a = { foo: { fpp: "bar" } };
b = Object.assign({}, a);
b.foo.fpp = "baz";

console.log(a.foo.fpp); // 印出baz

解構賦值


解構賦值是 ES6 以後的語法糖,同樣屬於淺拷貝

const a = { b: 1 };
const c = { ...a }; // 解構賦值
c.b = 2;
console.log(a); // { b: 1 }

得益於其精簡的代碼,實務上很常使用。





Deep copy


與前面提到的淺拷貝不同,深拷貝對於深層結構也能一併複製


早期的深拷貝

JSON.parse(JSON.stringify());

這個寫法大致上有以下缺點:

  • 忽略 function
  • 忽略原形鏈
  • 忽略 undefined
  • 子層太多會導致 stack overflow

儘管如此,由於已經可以處理大多狀況
如果不是為了性能或是特殊邏輯,此寫法已經夠用,是常見的深拷貝實現。


structuredClone

structuredClonenode.js 17 版以後支援的官方深拷貝實現

目前各大瀏覽器默認支援此語法

1


structuredClone 存在一些限制

不允許結構中存在 ErrorFunction 以及 DOM 對象

不保留 RegExp 對象的 lastIndex

不保留 read-only 等描述符,即無法限制 setters getters

不保留原形鏈

淺談 js 深拷貝與淺拷貝的差異

https://smilin.net/2023/09/15/deepCopyAndShallowCopy/

作者

Smilin

發佈於

2023-09-15

更新於

2023-09-18

許可協議

評論