深拷贝常用方法与循环引用问题

一、JSON.parse()与JSON.stringfy()方法

json序列化直接转化

const person = {
   name: 'seven',
   info: {
      age: 20
   }
}

const person1 = JSON.parse(JSON.stringify(person))
person.info.age = 18
person1.name = 'juejin'
console.log(person) // { name: 'seven', info: { age: 18 } }
console.log(person1) // { name: 'juejin', info: { age: 20 } }

存在问题:

  • (出现在非数组对象的属性值中时)undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略或者(出现在数组中时)被转换成 null。函数、undefined 被单独转换时,会返回 undefined,如 JSON.stringify(function(){}) 或者 JSON.stringify(undefined)
  • 对包含循环引用的对象(对象之间相互引用,形成无限循环)执行此方法,会抛出错误

二、递归遍历

const deepClone = (obj) => {
   // 定义递归的出口,如果源对象不是对象就返回 {}
   if (!obj || typeof obj !== 'object') {
      return {}
   }
   // 新的拷贝的数据,考虑数组和对象
   const newObj = Array.isArray(obj) ? [] : {}
   // 循环编译数组或对象的下标或者属性
   for (const key in obj) {
      const value = obj[key]
      // 如果属性值是对象那么递归进行深拷贝,否则直接赋值
      newObj[key] = typeof value === 'object' ? deepClone(value) : value
   }
   return newObj
}

const person = {
   name: 'seven',
   info: {
      age: 20
   }
}

const person1 = deepClone(person)
person1.name = 'jack'
person.info.age = 18
console.log(person) // { name: 'seven', info: { age: 18 } }
console.log(person1) // { name: 'jack', info: { age: 20 } }

存在问题:对象循环引用则会报 Maximum call stack size exceeded 调用栈溢出

三、对象循环引用问题

const deepClone = (obj) => {
   // 定义一个映射,初始化的时候将 obj 本身加入映射中
   const map = new WeakMap()
   map.set(obj, true)
   // 封装原来的递归逻辑
   const copy = (obj) => {
      if (!obj || typeof obj !== 'object') {
         return {}
      }
      const newObj = Array.isArray(obj) ? [] : {}
      for (const key in obj) {
         const value = obj[key]
         // 如果拷贝的是简单类型的值直接进行赋值
         if (typeof value !== 'object') {
            newObj[key] = value
         } else {
            // 如果拷贝的是复杂数据类型第一次拷贝后存入 map
            // 第二次再次遇到该值时直接赋值为 null,结束递归
            if (map.has(value)) {
               newObj[key] = null
            } else {
               map.set(value, true)
               newObj[key] = copy(value)
            }
         }
      }
      return newObj
   }
   return copy(obj)
}

// test
const seven = {
   name: 'seven'
}
const jack = {
   name: 'jack',
   relative: seven
}
seven.relative = jack
const newObj = deepClone(seven)
console.log(newObj)
// { name: 'seven', relative: { name: 'jack', relative: null } }

 

posted @ 2022-05-13 17:38  盼星星盼太阳  阅读(277)  评论(0)    收藏  举报