淺談JavaScript的 深拷貝和淺拷貝

深拷貝

深拷貝複製變量值,對於非基本類型的變量,則遞歸至基本類型變量後,再複製。 深拷貝後的對象與原來的對象是徹底隔離的,互不影響,對一個對象的修改並不會影響另外一個對象。javascript

淺拷貝

淺拷貝是會將對象的每一個屬性進行依次複製,可是當對象的屬性值是引用類型時,實質複製的是其引用,當引用指向的值改變時也會跟着變化。java

區別

淺拷貝和深拷貝都只針對於引用數據類型。數組

  • 淺拷貝只複製指向某個對象的指針,而不復制對象自己,新舊對象仍是共享同一塊內存;
  • 深拷貝會另外創造一個如出一轍的對象,跟原對象不共享內存,修改新對象不會改到原對象;
  • 區別:淺拷貝只複製對象的第一層屬性、深拷貝能夠對對象的屬性進行遞歸複製。
let obj = {
  name: 'Yvette',
  age: 18,
  hobbies: ['reading', 'photography']
}
let obj1 = obj
let obj2 = Object.assign({}, obj)
let obj3 = JSON.parse(JSON.stringify(obj))

obj.name = 'Jack'
obj.hobbies.push('coding')
console.log(obj) //{ name: 'Jack', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj1) //{ name: 'Jack', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj2) //{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography', 'coding' ] }
console.log(obj3) //{ name: 'Yvette', age: 18,hobbies: [ 'reading', 'photography' ] }
複製代碼

從以上例子能夠看出,當數據爲引用數據類型時函數

  1. 直接賦值屬於淺拷貝
  2. Object.assign,當數據第一層爲基本數據類型時,新的對象和原對象互不影響,可是若是第一層的屬性值是複雜數據類型,那麼新對象和原對象的屬性值其指向的是同一塊內存地址。
  3. JSON.parse(JSON.stringify(obj))可實現深拷貝

深拷貝的實現

  1. JSON.parse(JSON.stringify(obj)) 但存在一些缺陷
  • 對象的屬性值是函數時,沒法拷貝。
  • 原型鏈上的屬性沒法拷貝
  • 不能正確的處理 Date,RegExp 類型的數據
  • 會忽略 undefined
  1. 實現一個 deepClone 函數
  • 若是是基本數據類型,直接返回
  • 若是是 RegExp 或者 Date 類型,返回對應類型
  • 若是是複雜數據類型,遞歸。
  • 考慮循環引用的問題
function deepClone(obj, hash = new WeakMap()) {
  //遞歸拷貝
  if (obj instanceof RegExp) return new RegExp(obj)
  if (obj instanceof Date) return new Date(obj)
  if (obj === null || typeof obj !== 'object') {
    //若是不是複雜數據類型,直接返回
    return obj
  }
  if (hash.has(obj)) {
    return hash.get(obj)
  }
  /** * 若是obj是數組,那麼 obj.constructor 是 [Function: Array] * 若是obj是對象,那麼 obj.constructor 是 [Function: Object] */
  let t = new obj.constructor()
  hash.set(obj, t)
  for (let key in obj) {
    //遞歸
    if (obj.hasOwnProperty(key)) {
      //是不是自身的屬性
      t[key] = deepClone(obj[key], hash)
    }
  }
  return t
}
複製代碼

JavaScriptui

相關文章
相關標籤/搜索