深拷贝遇到循环引用怎么处理
先说什么是循环引用
两个对象存在相互引用的现象被称为循环引用,由于循环引用这些对象不能被垃圾回收机制回收,会导致内存泄漏
// 循环引用示例
let objA = { name: 'a' }
let objB = { name: 'b' }
objA.info = objB;
objB.info = objA;
如何解决循环引用,使其能被回收呢
点这里
深拷贝的方法有哪些
- lodash中的_.cloneDeep()
const _ = require('lodash');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);// false
- jQuery.extend()
const $ = require('jquery');
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false
- JSON.stringify()
这种方式有弊端会忽略undefined,symbol,function
const obj = {
name: 'A',
name1: undefined,
name3: function() {},
name4: Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}
- 手写循环递归
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
解决办法
可以使用weakMap,weakMap的键是弱引用,不会影响obj的存活状态
weakMap允许key是obj的形式,如果发现某个obj已经被记录过,就直接返回clone的obj,这样就不会无限循环递归导致内存溢出了