Array, Object的複製

Table of Contents

Table of Contents

一搜尋關於Array和Object的複製方法,馬上會出現多種的手段。 五花八門且還有deep copy(深拷貝), shallow copy(淺拷貝)之分,很令人困擾。

因此,這裡整理幾種可用方式做為參考。



deep copy & shallow copy

首先,使用" = "並不能實現複製效果,let b = a這樣子的作法,b跟a所指的是同一內容,所以當b去做內容變更的處理時,a也會跟著被改變。

例:原先的內容跟著被改變

let a = [1 ,2 ,3]
let b = a
b[0] = 0 // <-- 變更內容

console.log(a)
// > "a" Array [0, 2, 3]

console.log(b)
// > "b" Array [0, 2, 3]

What!? 本來為了不影響a,想複製一個b來做處理,結果a的值也被更改了。

因此,必須另外使用複製的方式去產生另一個一樣內容的東西。 而Array, Object又能包含多層結構,因此出現了 deep copyshallow copy 的作法。

先說結論,因為需求關係,能用deep copy是最好的,個人感覺最完美的是使用lodash來做deep copy。



最佳方法: Deep copy by lodash

使用lodash程式庫工具,他可以幫你完成 Deep copy 的效果。

首先,去lodash網站下載程式庫。

看使用場合選擇導入方式,這裡使用npm導入為例。

npm下載指令

npm i lodash

使用例

import _ from "lodash"

let target = [
    { id: 1, name: 'a', data: [1, 2, 3, 4], info: {age: 13, birth: '2020/01/01'}}
]

const deepCopyTarget = _.cloneDeep(target)


shallow copy: {...}

利用EC6的擴充運算子也可以完成shallow copy。 

let a = {id: 1, name: 'abc', age: 17}
let {...b} = a
b.id = 2

console.log('a', a)
// > "a" Object { id: 1, name: "abc", age: 17 }
console.log('b', b)
// > "b" Object { id: 2, name: "abc", age: 17 }

因為是shallow copy,所以更深一層結構的內容一樣會被更動。

let a =  { id: 1, name: 'a', data: [1, 2, 3, 4], info: {age: 13, birth: '2020/01/01'}}
let {...b} = a
b.id = 2
b.info.age = 0 // <-- a.info.age也會被變更

console.log('a', a)
// > "a" Object { id: 1, name: "a", data: Array [1, 2, 3, 4], info: Object { age: 0, birth: "2020/01/01" } }
console.log('b', b)
// > "b" Object { id: 2, name: "a", data: Array [1, 2, 3, 4], info: Object { age: 0, birth: "2020/01/01" } }


shallow copy .assign()

let a = {id: 1, name: 'abc', age: 17, getText: () =>  'text'}
let b = {}
Object.assign(b, a)
b.id = 2

console.log('a', a)
// > "a" Object { id: 1, name: "abc", age: 17, getText: () =>  'text' }
console.log('b', b)
// > "b" Object { id: 2, name: "abc", age: 17, getText: () =>  'text' }


shallow copy: JSON.parse() & JSON.stringify()

先取得複製的對象JSON文字化的結果後,再轉譯回來。 但無法複製函數的部分。



let a = {id: 1, name: 'abc', age: 17, getText: () =>  'text'}
let b = JSON.parse(JSON.stringify(a))
b.id = 2

console.log('a', a)
// "a" Object { id: 1, name: "abc", age: 17, getText: () =>  'text' }
console.log('b', b)
// "b" Object { id: 2, name: "abc", age: 17 }


shallow copy for Array

若複製對象是單純Array的話,可以用.slice() 或是 Array.from()來完成。



感想

根據場合來搭配使用是最好的。若確定內容架構只有單層,用Shallow copy即可,若是不止一層,那就選用Deep copy。

另外還有其他工具能完成deep copy,像是JQuery。lodash用來順手所以選擇它來使用。