先看一個例子:函數
// 對象類型在賦值的過程當中實際上是複製了地址,從而會致使改變了一方其餘也都被改變的狀況
let a = {
age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2
複製代碼
首先能夠經過 Object.assign
來解決這個問題,不少人認爲這個函數是用來深拷貝的。其實並非,Object.assign
只會拷貝全部的屬性值到新的對象中,若是屬性值是對象的話,拷貝的是地址,因此並非深拷貝。ui
let a = {
age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
複製代碼
另外咱們還能夠經過展開運算符 ...
來實現淺拷貝spa
let a = {
age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1
複製代碼
一般淺拷貝就能解決大部分問題了,可是當咱們遇到以下狀況就可能須要使用到深拷貝了code
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = { ...a }
a.jobs.first = 'native'
console.log(b.jobs.first) // native
複製代碼
淺拷貝只解決了第一層的問題,若是接下去的值中還有對象的話,那麼就又回到最開始的話題了,二者享有相同的地址。要解決這個問題,咱們就得使用深拷貝了。對象
這個問題一般能夠經過 JSON.parse(JSON.stringify(object))
來解決。遞歸
let a = {
age: 1,
jobs: {
first: 'FE'
}
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
複製代碼
可是該方法有侷限性:原型鏈
undefined
symbol
在遇到函數、 undefined
或者 symbol
的時候,該對象也不能正常的序列化原型
let a = {
age: undefined,
sex: Symbol('male'),
jobs: function() {},
name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}
複製代碼
你會發如今上述狀況中,該方法會忽略掉函數和 undefined
,可是在一般狀況下,複雜數據都是能夠序列化的,因此這個函數能夠解決大部分問題。string
若是你所需拷貝的對象含有內置類型而且不包含函數,最好的方式是推薦[lodash 的深拷貝函數]
,由於實現一個深拷貝是很困難的,須要考慮好多種邊界狀況,好比原型鏈如何處理、DOM 如何處理等等it
在此實現一個簡易版的深拷貝
// 遞歸拷貝
function deepClone(obj) {
let copy = obj instanceof Array ? [] : {}
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
}
return copy
}
複製代碼