JavaScript中的手写深拷贝
完整版:
function deepCopy(obj, cache = new WeakMap()) {
// 支持值类型
// 与值类型相对的是对象类型,对象是指内存中的可以被标识符引用的一块区域
if (!obj instanceof Object) return obj;
// 防止循环引用
if (cache.get(obj)) return cache.get(obj);
// 支持函数
if (obj instanceof Function) {
return function () {
return obj.apply(this, arguments);
};
}
// 支持日期
if (obj instanceof Date) return new Date(obj);
// 支持正则
if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);
// 支持Map
if (obj instanceof Map) {
const result = new Map();
cache.set(obj, result);
obj.forEach((val, key) => {
// 注意:map中的值为object的话也得深拷贝
if (val instanceof Object) {
result.set(key, deepCopy(val, cache));
} else {
result.set(key, val);
}
});
return result;
}
// 支持Set
if (obj instanceof Set) {
const result = new Set();
cache.set(obj, result);
obj.forEach((val) => {
// 注意:set中的值为object的话也得深拷贝
if (val instanceof Object) {
result.add(deepCopy(val, cache));
} else {
result.add(val);
}
});
return result;
}
// 数组是 key 为数字索引的特殊对象
const res = Array.isArray(obj) ? [] : {};
// 缓存 copy 的对象,用于处理循环引用的情况
cache.set(obj, res);
Object.keys(obj).forEach((key) => {
if (obj[key] instanceof Object) {
res[key] = deepCopy(obj[key], cache);
} else {
res[key] = obj[key];
}
});
return res;
}
// 测试
const source = {
name: "Jack",
meta: {
age: 12,
birth: new Date("1997-10-10"),
ary: [1, 2, { a: 1 }],
say() {
console.log("Hello");
},
},
};
source.source = source;
const newObj = deepCopy(source);
console.log("newObj: ", newObj);
console.log(newObj.meta.ary[2] === source.meta.ary[2]); // false
console.log(newObj.meta.birth === source.meta.birth); // false
console.log(
"new Map(): ",
new Map([
["number", "数字"],
["string", "字符串"],
[{ obj: "对象" }, "对象作为键"],
])
);
console.log("new Set(): ", new Set([1, 2, 3, 1, "2"]));
简单版:
function deepCopy(obj) {
let newObj = Array.isArray(obj)?[]:{};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === "object") {
newObj[key] = deepCopy(obj[key]);
} else {
newObj[key] = obj[key];
}
}
}
return newObj
}
let obj_02 = deepCopy(obj_01);