在JavaScript中,深拷贝(Deep Copy)浅拷贝(Shallow Copy) 是处理对象和数组复制时非常重要的概念。理解它们的区别,对于避免数据意外修改、提高代码健壮性至关重要。


一、基本概念

1. 浅拷贝(Shallow Copy)

  • 只复制对象的第一层属性
  • 对于对象中的基本数据类型(如 stringnumberboolean),会复制值。
  • 对于对象中的引用类型(如对象、数组),只复制引用地址,而不是创建新的对象。
  • 因此,原对象和拷贝对象共享嵌套对象的引用,修改嵌套对象会影响彼此。

2. 深拷贝(Deep Copy)

  • 递归复制对象的所有层级
  • 不仅复制第一层,还会深入复制所有嵌套的对象和数组。
  • 原对象和拷贝对象完全独立,互不影响。

二、示例对比

示例:浅拷贝

const original = {name: "Alice",info: {age: 25,hobbies: ["reading", "coding"]}
};// 浅拷贝方法1:使用 Object.assign
const shallowCopy = Object.assign({}, original);// 浅拷贝方法2:使用展开运算符
const shallowCopy2 = { ...original };// 修改浅拷贝的嵌套对象
shallowCopy.info.age = 30;
shallowCopy.name = "Bob";console.log(original.name);           // "Alice" ✅(基本类型不受影响)
console.log(original.info.age);       // 30 ❌(引用类型被修改了!)

⚠️ 结论:修改 shallowCopy.info.age 影响了原对象,因为 info 是引用类型,只复制了指针。


示例:深拷贝

const original = {name: "Alice",info: {age: 25,hobbies: ["reading", "coding"]}
};// 方法1:JSON 序列化(简单但有限制)
const deepCopy1 = JSON.parse(JSON.stringify(original));// 方法2:递归函数实现(更灵活)
function deepClone(obj) {if (obj === null || typeof obj !== 'object') return obj;if (obj instanceof Date) return new Date(obj);if (obj instanceof Array) return obj.map(item => deepClone(item));if (typeof obj === 'object') {const cloned = {};for (let key in obj) {if (obj.hasOwnProperty(key)) {cloned[key] = deepClone(obj[key]);}}return cloned;}
}const deepCopy2 = deepClone(original);// 修改深拷贝
deepCopy2.info.age = 30;
deepCopy2.name = "Bob";console.log(original.name);           // "Alice" ✅
console.log(original.info.age);       // 25 ✅(未受影响)

✅ 深拷贝后,修改拷贝对象不会影响原对象。


三、常见拷贝方法分析

方法 类型 是否深拷贝 局限性
Object.assign() 浅拷贝 只复制第一层
{...obj} 展开语法 浅拷贝 同上
Array.prototype.slice() 浅拷贝 数组专用,嵌套对象仍共享
JSON.parse(JSON.stringify(obj)) 深拷贝 无法处理函数、undefined、Symbol、循环引用、Date 特殊对象
递归函数 深拷贝 灵活,可自定义处理类型
structuredClone()(现代浏览器) 深拷贝 支持大多数类型(包括 Date、RegExp),但不支持函数

四、推荐深拷贝方案

✅ 推荐1:使用 structuredClone()(现代标准)

const original = { name: "Alice", info: { age: 25 } };
const deepCopy = structuredClone(original);

✅ 支持:Date、RegExp、Map、Set、Array、对象等
❌ 不支持:函数、Error 对象、DOM 节点

✅ 推荐2:自定义深拷贝函数(处理复杂需求)

function deepClone(obj, hash = new WeakMap()) {if (obj === null || typeof obj !== 'object') return obj;if (hash.has(obj)) return hash.get(obj); // 处理循环引用let cloned;if (obj instanceof Date) cloned = new Date(obj);else if (obj instanceof RegExp) cloned = new RegExp(obj);else if (obj instanceof Array) cloned = obj.map(item => deepClone(item, hash));else if (typeof obj === 'object') {cloned = {};hash.set(obj, cloned); // 记录已克隆对象for (let key in obj) {if (obj.hasOwnProperty(key)) {cloned[key] = deepClone(obj[key], hash);}}}return cloned;
}

✅ 支持循环引用、多种内置对象


五、什么时候用深拷贝?什么时候用浅拷贝?

场景 建议
只读数据、简单对象 浅拷贝足够
需要修改嵌套结构 深拷贝
状态管理(如 Redux) 深拷贝或使用不可变更新
表单数据备份 深拷贝更安全
性能敏感场景 浅拷贝 + 按需深拷贝

六、总结:一句话区别

浅拷贝:只复制表面,嵌套对象共用;
深拷贝:里里外外全复制,完全独立。


七、常见误区

  1. const copy = obj 不是拷贝,只是引用赋值。
  2. JSON.parse(JSON.stringify(obj)) 不能处理函数和循环引用。
  3. ✅ 深拷贝性能开销大,不要滥用。

最佳实践建议

  • 优先使用 structuredClone()(现代项目)
  • 复杂场景使用自定义深拷贝
  • 简单场景可用浅拷贝 + 注意嵌套修改

通过理解深浅拷贝,你可以更好地控制数据状态,避免“改了一个地方,其他地方莫名其妙变了”的 bug!