一、JSON.parse(JSON.stringify())进行深拷贝的缺点
1、函数、undefined 、Symbol 被忽略
const obj = {
func: () => console.log("Hello"),
undef: undefined,
sym: Symbol("foo"),
name: '张三',
age: 0,
sex: null
};
const copy = JSON.parse(JSON.stringify(obj));
console.log(copy); // 👉 { name: '张三', age: 0, sex: null }
2、Date 对象被转为字符串
const obj = {
date: new Date()
};
console.log(obj.date.getFullYear()) // 👉 2025
const copy = JSON.parse(JSON.stringify(obj));
console.log(obj); // 👉 {date: '2025-07-19T01:44:17.445Z'}
console.log(copy.date.getFullYear()) // 👉 Date 对象被转为字符串,方法无法使用,会报错
3、NaN / Infinity 转为 null
const obj = {
num: NaN, inf: Infinity
};
const copy = JSON.parse(JSON.stringify(obj));
console.log(copy); // 👉 { num: null, inf: null }
4、循环引用不能被拷贝
const obj = { name: "循环引用" };
obj.self = obj; // 自引用
const copy = JSON.parse(JSON.stringify(obj)); // 👉 报错 -- TypeError: Converting circular structure to JSON
5、原型链断裂
function Person (name) {
this.name = name;
}
Person.prototype.greet = function () { console.log(`Hi, ${this.name}!`); };
const alice = new Person("Alice");
alice.greet() // 👉 "Hi, Alice!"
const copy = JSON.parse(JSON.stringify(alice));
copy.greet(); // 原型方法丢失,会报错: TypeError: copy.greet is not a function
6、会将RegExp 和 Error 转为空对象
const obj = {
regex: /abc/g,
err: new Error("test")
};
const copy = JSON.parse(JSON.stringify(obj));
console.log(copy); // 👉 { regex: {}, err: {} }
7、Map / Set 数据丢失
const obj = { map: new Map([["key", "value"]]) };
const copy = JSON.parse(JSON.stringify(obj));
console.log(copy); // 👉 { map: {} }
二、解决方法
1、方法一:用递归进行拷贝
function deepClone (source, map = new WeakMap()) {
// 处理循环引用
if (map.has(source)) return map.get(source);
// 处理原始类型和 null/undefined
if (source === null || typeof source !== "object") {
return source; // 直接返回函数、Symbol 和原始值
}
// 处理特殊类型对象
if (source instanceof Date) return new Date(source);
if (source instanceof RegExp) return new RegExp(source);
if (source instanceof Map) {
return new Map(Array.from(source.entries()).map(([k,v])=>[deepClone(k),deepClone(v)]))
}
// 创建新对象并保留原型链
const clone = Object.create(Object.getPrototypeOf(source))
map.set(source, clone); // 缓存引用
// 递归拷贝属性(包括 Symbol 键)
Reflect.ownKeys(source).forEach(key => {
clone[key] = deepClone(source[key], map);
});
return clone;
}
// 例
const obj = {
func: () => console.log("Hello"),
undef: undefined,
sym: Symbol("foo")
};
const copy = deepClone(obj);
copy.a = 3
console.log(copy) // 👉 {undef: undefined, sym: Symbol(foo), a: 3, func: ƒ} console.log(obj) // 👉 {undef: undefined, sym: Symbol(foo), func: ƒ}
2、方法二:structuredClone
① structuredClone 仍无法复制 函数 和 Symbol ② 原型链不会保留原型链
// 例
const obj = { date: new Date() };
const clonedSink = structuredClone(obj)
console.log(clonedSink.date.getFullYear()) // 👉 2025