Skip to content

Shallow VS Deep Copy 淺拷貝與深拷貝

簡單說

淺拷貝 只是 傳址 (by reference) 或 拷貝到第一層,還是會受到 來源 修改的連動影響; 深拷貝 拷貝的目標將會是獨立的個體,不會與來源有任何連動。

Shallow copy 淺拷貝

拷貝後目標 局部或全部都為 傳址 by reference ,會受到 來源資料 連動修改的影響。

= 賦值

copyObj 會受到 obj 修改的連動影響

js
let obj = { id: 1 }
let copyObj = obj

// 修改屬性
obj.id = 9
console.log(obj) // {id: 9}
console.log(copyObj) // {id: 9}

Object.assign

僅有第一維有完全 復製 ,第二維之後都是 傳址 by reference,會受到修改連動影響。

js
let obj = { id: 1, obj2: { id: 2 } }
let copyObj = Object.assign({}, obj)

// 第一維修改
obj.id = 999
console.log(obj.id) // 999
console.log(copyObj.id) // 1

// 第二維修改
obj.obj2.id = 999
console.log(obj.obj2.id) // 999
console.log(copyObj.obj2.id) // 999

Spread Operator 展開運算子

其實是跟 Object.assign 完全一樣的能力,只有第一維是完全不受到連動影響。

js
let obj = { id: 1, obj2: { id: 2 } }
let copyObj = { ...obj }

// 第一維修改
obj.id = 999
console.log(obj.id) // 999
console.log(copyObj.id) // 1

// 第二維修改
obj.obj2.id = 999
console.log(obj.obj2.id) // 999
console.log(copyObj.obj2.id) // 999

Deep copy 深拷貝

拷貝後目標 完全不受到 來源資料 修改連動的影響且獨立運作。

JSON 字串化與解析還原

這個方法,是將物件轉換成單純的 字串 使其不具有 傳址 by reference 特性,再轉換為原本的 物件 型態,所有屬性都會是另外的記憶體,不受修改連動影響。

js
let obj = { id: 1, obj2: { id: 2 } }
let copyObj = JSON.parse(JSON.stringify(obj))

// 第一維修改
obj.id = 999
console.log(obj.id) // 999
console.log(copyObj.id) // 1

// 第二維修改
obj.obj2.id = 999
console.log(obj.obj2.id) // 999
console.log(copyObj.obj2.id) // 2

注意

這個方法僅適用於沒有 函式 屬性的物件格式,字串化的物件是無法還原 函式 的。

缺點

  • 無法拷貝 函式
  • 無法拷貝 原型鏈

structuredClone 深拷貝

這是最新用來處理「深拷貝」的原生語法,如果物件結構是較大較復雜的情況,使用 structuredClone 效能與速度會更優於 JSON.stringify

特點

  • 不可拷貝函式
  • 不保留原型鏈

語法

structuredClone 本身會回傳拷貝後的物件。

structuredClone(<將拷貝的物件>)

js
const obj = {
  id: 1,
  name: 'naiky',
  data: {
    age: 37,
  },
}

// 深拷貝
const strterObj = structuredClone(obj)

注意

當拷貝 functionErrorDOM,會報錯 Uncaught DOMException: Failed to execute 'structuredClone' on 'Window':

Reference