浅拷贝只复制第一层属性,嵌套引用仍共享内存;深拷贝递归复制所有层级,完全独立。浅拷贝方法有展开运算符、Object.assign()、slice()/concat(),但不支持嵌套及特殊类型;深拷贝需处理递归、特殊类型和循环引用,推荐使用_.cloneDeep()或structuredClone()。

浅拷贝只复制对象的第一层属性,新旧对象的嵌套引用仍然指向同一内存地址;深拷贝则递归复制所有层级,新对象与原对象完全独立,互不影响。
浅拷贝的典型表现和常用方法
对一个包含对象或数组的变量做浅拷贝后,修改嵌套内容会影响原对象。常见实现方式有:
- 展开运算符(…):适用于对象和数组,如
{...obj}或[...arr] - Object.assign():第一个参数是目标对象,如
Object.assign({}, obj) - Array.prototype.slice() / concat():仅适用于一维数组
注意:这些方法都无法处理嵌套对象、函数、undefined、symbol、date、regexp 等特殊类型,且对循环引用无能为力。
深拷贝的核心难点与基础实现
真正可靠的深拷贝需解决三类问题:嵌套结构递归处理、特殊类型识别还原、循环引用检测。一个简易但实用的手写版本如下:
立即学习“Java免费学习笔记(深入)”;
function deepClone(obj, map = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; if (map.has(obj)) return map.get(obj); let cloned; if (obj instanceof Date) { cloned = new Date(obj); } else if (obj instanceof RegExp) { cloned = new RegExp(obj); } else if (Array.isArray(obj)) { cloned = []; } else { cloned = {}; } map.set(obj, cloned); for (let key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { cloned[key] = deepClone(obj[key], map); } } return cloned; }
这个版本支持普通对象、数组、Date、RegExp,并用 WeakMap 防止循环引用导致的栈溢出。
生产环境推荐方案
手写深拷贝易出错,多数项目建议优先使用成熟方案:
- jsON.parse(json.stringify(obj)):最简方式,但会丢失函数、undefined、Symbol、Date 对象(变成字符串)、NaN、Infinity,且不支持循环引用
- Lodash 的 _.cloneDeep():功能全面,兼容各种边界情况,经过大量测试
- structuredClone()(现代浏览器):原生 API,支持 Map、Set、Date、RegExp、ArrayBuffer 等,但暂不支持函数和 undefined
若需支持函数或自定义逻辑,可基于 structuredClone + 自定义序列化器扩展,或选用更灵活的库如 clone-deep。
基本上就这些。深拷贝看似简单,实际涉及类型判断、递归控制、内存管理等细节,日常开发中按需选择即可。