深拷贝常用方法与循环引用问题
一、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 } }

浙公网安备 33010602011771号