這是上一篇 [JavaScript] 引用 vs 復(fù)制 的后續(xù)。
淺克隆
上一篇中說的 = 和 Object.assign() 包括 ES6 的 spread operator 都是淺克隆,= 只會(huì)對(duì)原對(duì)象進(jìn)行引用,后兩種方法只會(huì)對(duì)對(duì)象的第一層進(jìn)行克隆。
深度克隆
深度克隆指生成一個(gè)獨(dú)立的對(duì)象,和原對(duì)象之間不會(huì)互相影響。
對(duì)一個(gè)對(duì)象深度克隆,完全取決于你所要拷貝的數(shù)據(jù)類型。
let obj = {
a: 1,
b: {
c: 1
}
}
let obj2 = JSON.parse(JSON.stringify(obj))
上面的例子是可以實(shí)現(xiàn)深度克隆的,但是它的缺陷是只能復(fù)制對(duì)象返回的值,不能對(duì)實(shí)例進(jìn)行復(fù)制。
let obj = {
name: 'Bob',
date: {
now: new Date()
}
}
let obj2 = JSON.parse(JSON.stringify(obj))
這個(gè)例子中,當(dāng)我們要復(fù)制一個(gè) Date 實(shí)例時(shí),JSON.parse(JSON.stringify(obj)) 只會(huì)先把實(shí)例返回的值轉(zhuǎn)成字符串,然后再轉(zhuǎn)換成對(duì)象,所有 Date 支持的方法和繼承的方法都是沒有被克隆的。最后的結(jié)果 obj2.date.now 只是一個(gè)字符串顯示了你復(fù)制時(shí)的時(shí)間。
通過 NodeJs Serialization API 實(shí)現(xiàn)深度克隆
可以使用 nodejs API 來實(shí)現(xiàn)深度克隆。v8 是 nodejs version 8 新加的庫(kù)。其中包含了 serialize 和 deserialize 方法,實(shí)現(xiàn)深度克隆。
const v8 = require('v8')
let obj = {
name: 'Bob',
date: {
now: new Date()
}
}
let obj2 = v8.deserialize(serialize(obj))
通過第三方函數(shù)庫(kù)實(shí)現(xiàn)深度克隆
Loadash
const cloneDeep = require('lodash.cloneDeep')
let obj2 = cloneDeep(obj)
類似的函數(shù)庫(kù)還有很多,比如 Underscore,Ramda 都提供了 deep clone 的方法。
原理
Deep clone 并不是完美的,目前大部分方法都是基于結(jié)構(gòu)化克隆算法(The structured clone algorithm)。
算法有局限性,可以通過查閱文檔來判斷是否滿足需求。