深拷貝(deepClone)淺拷貝(shallowCopy)

先看一個例子:函數

// 對象類型在賦值的過程當中實際上是複製了地址,從而會致使改變了一方其餘也都被改變的狀況
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
}
複製代碼
相關文章
相關標籤/搜索