js深拷贝与循环引用
在 JavaScript 中,深拷贝(deep copy)意味着创建一个新的对象,并递归地复制原始对象的所有属性,包括嵌套的对象和数组。深拷贝确保原始对象和副本之间不共享任何引用,因此修改副本不会影响原始对象。
然而,当原始对象中存在循环引用时,深拷贝的实现可能会变得复杂。循环引用是指两个或多个对象相互引用,形成一个闭环。在这种情况下,深拷贝函数需要能够识别并处理循环引用,以避免无限循环。
function deepCopy(target) {
var arr = []; // use array store the used refrence, and avoid repeat
return _deepCopy(target);
function _deepCopy(target) {
let result = {};
for (let k in target) {
if (target.hasOwnProperty(k)) {
if (target[k] && typeof target[k] === 'object') {
if ((arr.filter(v=>v === target[k])).length === 0) {
arr.push(target[k]);
result[k] = _deepCopy(target[k]);
}
} else {
result[k] = target[k];
}
}
}
return result;
}
}
// test code
var a = {
n: 1,
m: 2
};
var b = {
m: 1,
n: 2
};
a.b = b;
b.a = a;
var c = deepCopy(a);
另外,我们可以在深拷贝函数中使用一个映射(如 Map 或 WeakMap)来跟踪已经拷贝过的对象。以下是一个处理循环引用的深拷贝函数的示例:
function deepCopy(obj, map = new WeakMap()) {
if (obj === null) return null; // 处理 null 值
if (typeof obj !== 'object') return obj; // 处理非对象值
if (map.has(obj)) return map.get(obj); // 处理循环引用
const clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone); // 记录当前对象的副本
Object.keys(obj).forEach((key) => {
clone[key] = deepCopy(obj[key], map); // 递归拷贝对象的属性
});
return clone;
}
增加对 RegExp和Date类型的处理
function deepCopy(target) {
var arr = [];
return _deepCopy(target);
function _deepCopy(target) {
let result = {};
for (let k in target) {
if (target.hasOwnProperty(k)) {
let obj = target[k];
if (obj && typeof obj === 'object') {
if ((arr.filter(v=>v === obj)).length === 0) {
arr.push(obj);
// copy RegExp
if (obj instanceof RegExp) {
result[k] = new RegExp(obj);
}
// copy Date
else if (obj instanceof Date) {
result[k] = new Date(obj);
} else {
result[k] = _deepCopy(target[k]);
}
}
} else {
result[k] = target[k];
}
}
}
return result;
}
}
var a = {
n: 1,
m: 2
};
var b = {
m: 1,
n: 2,
r: /a/,
d: new Date()
};
a.b = b;
b.a = a;
var c = deepCopy(a);
WeakMap去重版
// WeakMap
function deepCopy(target) {
var hash = new WeakMap(); // use WeakMap store the used refrence, and avoid repeat
return _deepCopy(target);
function _deepCopy(target) {
let result = {};
for (let k in target) {
if (target.hasOwnProperty(k)) {
let obj = target[k];
if (obj && typeof obj === 'object') {
if ( !hash.has(obj)) {
hash.set(obj, 1);
// copy RegExp
if (obj instanceof RegExp) {
result[k] = new RegExp(obj);
}
// copy Date
else if (obj instanceof Date) {
result[k] = new Date(obj);
} else {
result[k] = _deepCopy(target[k]);
}
}
} else {
result[k] = target[k];
}
}
}
return result;
}
}
深拷贝与浅拷贝与不拷贝
假设有个对象 let a = {a: { a: 1}}
; 我们要生成另外一个对象b;
- 不拷贝: let b = a; 这是不拷贝,因为b和a是同一个引用,没有任何拷贝操作发生;如果给b添加一个新属性
b.b=1;
; 那么对象a也会添加一个新属性b且 a.b===1;
-
浅拷贝
-
深拷贝 不再解释了。
添加对数组的处理
function deepCopy(target) {
var hash = new WeakMap();
// use WeakMap store the used refrence, and avoid repeat
return _deepCopy(target);
function _deepCopy(target) {
let result = {};
for (let k in target) {
if (target.hasOwnProperty(k)) {
let obj = target[k];
if (obj && typeof obj === 'object') {
if (!hash.has(obj)) {
hash.set(obj, 1);
// copy RegExp
if (obj instanceof RegExp) {
result[k] = new RegExp(obj);
}// copy Date
else if (obj instanceof Date) {
result[k] = new Date(obj);
} // copy Array
else if (obj instanceof Array) {
let arr = [];
obj.forEach(v=>{
arr.push(deepCopy(v));
}
);
result[k] = arr;
} else {
result[k] = _deepCopy(target[k]);
}
}
} else {
result[k] = target[k];
}
}
}
return result;
}
}