簡單去解釋的話,淺拷貝與深拷貝最大的差異在於 Global Object (以下簡稱 GO) 上的複製引用賦值與記憶體位址,原始值的依賴關係 而深淺拷貝所對應的資料操作型別僅限於 Array, Object 這樣的複合型資料結構

淺拷貝:

其操作對象僅限於 Array, Object ,同時賦值引用狀況不同,其深淺拷貝的狀態也不同 Ex:

const obj1 = { name: "string", value: 2, nested: { a: 4 } };
const obj2 = obj1;

const obj2.name = "newString"
// obj1 = { name: "newString", value: 2, nested: { a: 4 } };

當如同 obj2 一般的引用時,就都屬於淺拷貝 只有資料是巢狀型態時深拷貝,但 nested 由於是巢狀資料,nested 的下一層會是引用 obj1 的記憶體位址,此時上一層的 name, value 在記憶體位址上是新的位址,並不是引用於 obj1

const foo = { name: "stirng", value: 123 };
const bar = Object.assgin({}, foo);
const bar_1 = { ...foo };

上述皆屬於淺拷貝的範疇,在 GO 的運作機制上 foo, bar, bar_1 的記憶體位址是共同持有的,bar, bar_1 是引用 foo ,但三者任一發生了資料更新變動時,所有 variable 被訪問的值都會是被重新賦值後的 value Ex:

const foo = { name: "stirng", value: 123 };
const bar = Object.assgin({}, foo);
const bar_1 = { ...foo };

bar.value = 444;
console.log(foo.value); // 444
console.log(bar.value); // 444
console.log(bar_1.value); // 444

cosnt a = [1,2,3,4]
const b = a

a.push(5)
console.log(a) // [1, 2, 3, 4, 5]
console.log(b) // [1, 2, 3, 4, 5]

深拷貝:

對應 React, Vue 等現代框架的 Data immutable 理念來說,就是深拷貝的一種大量封裝應用方式,原因在於現代框架利用 vDom 的特性做前後比對,針對變動資料單獨渲染,以降低實際渲染上的時間損耗,提升使用體用 而這些與深拷貝的特性不謀而合,不論如何進行資料操作,其本身都是在 GO 開闢一塊新的記憶體位址儲存操作後的資料。原始資料並不會發生任何改動,直到 JS Runtime 該值的沒有其他引用後進行回收銷毀。

但有些狀況深拷貝的資料結構可能會發生改變,例如:

const obj1 = { name: "string", value: 2, nested: { a: 4 } };
const obj2 = { ...obj1 };

obj2.nested.a = 5;
// obj1 = { name: "string", value: 2, nested: { a: 5 } };
// obj2 = { name: "string", value: 2, nested: { a: 5 } };

當使用 Spread Syntax 來解構並賦值時,資料若是巢狀那麼深拷貝僅會執行在 Spread 所訪問的資料層級,向下的巢狀結構將會用淺拷貝來執行,此時若是直接改動 nested 就會連帶改動到 obj1 的 nested 值 PS: 當 nested 這個 key value 賦值後的資料型態是複合型別時 (Array, Object) 賦值特性仍是淺拷貝,但重新賦值的資料型別屬於Array, Object 時,就會成深拷貝的特性,這樣的賦值將不會去更動到 obj1 的原始資料