如何深度克隆JavaScript對象

JavaScript提供了許多複制對象的方法,但並非所有方法都提供了深層複製。學習最有效的方法,並找出所有可用的選項

用JavaScript複製對象可能很棘手。有些方法執行淺表複製,這是大多數情況下的默認行為。

深拷貝與淺拷貝

淺表複製成功複製基本類型像數字和字符串一樣,但是不會遞歸地複制任何對象引用,而是新復制的對象將引用相同的對象。

如果一個對象引用了其他對象,則在執行淺拷貝對象的,你複製參考到外部對象。

當執行一個深拷貝, 那些外部對像也被複製,因此,新的克隆對象完全獨立於舊對象。

搜索如何在Internet上的JavaScript中深度克隆對象,您會找到很多答案,但是答案是並不總是正確的

最簡單的選擇:使用Lodash

我建議執行深度複製是依靠經過充分測試,非常流行且經過精心維護的庫:Lodash。

Lodash提供了非常方便的clonedeepclone用於執行淺層和深層克隆的功能。

Lodash具有以下出色功能:您可以分別導入單個功能在您的項目中減少了很多依賴項。

在Node.js中:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

這是一個顯示正在使用的兩個功能的示例:

const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')

const externalObject = { color: ‘red’, }

const original = { a: new Date(), b: NaN, c: new Function(), d: undefined, e: function () {}, f: Number, g: false, h: Infinity, i: externalObject, }

const cloned = clone(original)

externalObject.color = ‘blue’

console.info(‘⬇️ shallow cloning 🌈’) console.info( ‘✏️ Notice the i.color property we changed on original is also changed in the shallow copy’ ) console.log(original) console.log(cloned)

const deepcloned = clonedeep(original)

externalObject.color = ‘yellow’ console.log(’’) console.info(‘⬇️ deep cloning 🌈’) console.info(‘✏️ Notice the i.color property does not propagate any more’) console.log(original) console.log(deepcloned)

在這個簡單的示例中,我們首先創建一個淺表副本,然後編輯i.color屬性,該屬性傳播到復制的對象。

在深度克隆中,這不會發生。

Object.assign()

Object.assign()執行對象的淺表副本,而不是深層副本。

const copied = Object.assign({}, original)

作為淺表副本,將克隆值並複制對象引用(而不是對象本身),因此,如果在原始對像中編輯對象屬性,則在復制的對像中也將對其進行修改,因為引用的內部對像是相同的:

const original = {
  name: 'Fiesta',
  car: {
    color: 'blue',
  },
}
const copied = Object.assign({}, original)

original.name = ‘Focus’ original.car.color = ‘yellow’

copied.name //Fiesta copied.car.color //yellow

使用對像傳播運算符

點差算子是一個ES6 / ES2015該功能提供了執行淺層克隆的非常方便的方法,等效於Object.assign()做。

const copied = { ...original }

錯誤的解決方案

在網上您會發現很多建議。這是一些錯誤的:

使用Object.create()

注意:不推薦

const copied = Object.create(original)

這是錯誤的,它不執行任何復制。

相反,original對像被用作原型copied

顯然,它可以工作,但是在幕後它卻不是:

const original = {
  name: 'Fiesta',
}
const copied = Object.create(original)
copied.name //Fiesta

original.hasOwnProperty('name') //true
copied.hasOwnProperty('name') //false

查看更多Object.create()

JSON序列化

注意:不推薦

一些建議轉換為JSON格式

const cloned = JSON.parse(JSON.stringify(original))

但這會帶來意想不到的後果。

通過這樣做,您將失去JSON中沒有等效類型的任何Javascript屬性,例如Function或者Infinity。分配給的任何屬性undefined將被忽略JSON.stringify,導致它們在克隆對像上丟失。

此外,某些對象會轉換為字符串,例如Date對象(同樣,不考慮時區,默認為UTC),Set,Map等許多其他對象:

JSON.parse(
  JSON.stringify({
    a: new Date(),
    b: NaN,
    c: new Function(),
    d: undefined,
    e: function () {},
    f: Number,
    g: false,
    h: Infinity,
  })
)

Parsing as JSON

僅當您沒有任何內部對象和函數,而只有值時,這才起作用。

免費下載我的JavaScript初學者手冊


更多js教程: