在 JavaScript 中,深拷贝(Deep Copy)是一种创建对象完整副本的方式,其中所有的嵌套对象或数组也会被拷贝,而不是共享原始对象的引用。以下是一些常见的深拷贝方法:
1. JSON 方法
使用 JSON.stringify() 和 JSON.parse() 将对象转换为 JSON 字符串后再解析为新对象。
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));
console.log(deepCopy); // { a: 1, b: { c: 2 } }
console.log(deepCopy.b === obj.b); // false
优点:
简单易用,适合纯 JSON 结构(不含函数、undefined、Symbol 等)。
缺点:
不能处理循环引用(如 obj.a = obj)。丢失特殊数据类型(如 Date、Set、Map 等)。
2. 递归拷贝
手动实现递归拷贝,适合处理更复杂的数据结构。
function deepCopy(obj) {
if (obj === null || typeof obj !== "object") return obj;
// 处理数组
if (Array.isArray(obj)) {
return obj.map(item => deepCopy(item));
}
// 处理对象
const copy = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopyObj = deepCopy(obj);
console.log(deepCopyObj); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopyObj.b === obj.b); // false
优点:
- 可完全控制深拷贝的行为。
- 能处理循环引用(需要额外的逻辑)。
缺点:
- 实现复杂,需要处理特殊情况(如循环引用)。
3. 使用第三方库
Lodash 的 cloneDeepLodash 提供了一个高效且功能强大的深拷贝方法。
const _ = require("lodash");
const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopy = _.cloneDeep(obj);
console.log(deepCopy); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopy.b === obj.b); // false
优点:
- 处理各种数据类型和特殊情况(如循环引用)。
- 使用简单且可靠。
缺点:
- 需要额外引入库
4. 结合 structuredClone
structuredClone 是一个现代浏览器支持的内置方法,用于深拷贝。
const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopy = structuredClone(obj);
console.log(deepCopy); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopy.b === obj.b); // false
优点:
- 原生支持,无需外部库。
- 支持 Map、Set、Date 等数据类型。
- 能处理循环引用。
缺点:
- 需要现代浏览器支持(不支持 IE 等老旧浏览器)。
5. 使用 Object.assign 或扩展运算符结合递归
结合 Object.assign 或展开运算符,实现手动深拷贝。
function deepCopy(obj) {
if (obj === null || typeof obj !== "object") return obj;
const copy = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopyObj = deepCopy(obj);
console.log(deepCopyObj); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopyObj.b === obj.b); // false
优点:
- 与递归方法类似,但结合了更直观的语法。
缺点:
- 仍需处理特殊数据类型和循环引用。
6. 手动处理特殊数据类型
针对特定场景(如 Date、Map、Set),手动处理深拷贝。
function deepCopy(obj) {
if (obj === null || typeof obj !== "object") return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof Map) return new Map([...obj]);
if (obj instanceof Set) return new Set([...obj]);
const copy = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
const obj = { a: new Date(), b: new Map([[1, "one"]]), c: new Set([2, 3]) };
const deepCopyObj = deepCopy(obj);
console.log(deepCopyObj); // 深拷贝的对象,保持特殊类型