浅拷贝只断开第一层引用,深拷贝递归复制所有层级实现完全独立;前者用展开运算符或Object.assign(),后者推荐structuredClone(),JSON法有类型丢失缺陷,循环引用需WeakMap缓存避免栈溢出。

JavaScript中浅拷贝只复制对象的第一层引用,深拷贝则递归复制所有嵌套层级,使新旧对象完全独立——这是两者最核心的区别,关键在于“引用是否被切断”。
浅拷贝:只断开第一层引用
浅拷贝创建一个新对象,把原对象第一层的属性值(基本类型直接复制值,引用类型复制地址)拷贝过去。因此,如果原对象有嵌套对象,新对象仍指向同一内存地址。
常见实现方式:
-
展开运算符(...):
const newObj = {...oldObj},仅适用于对象字面量和可枚举自有属性 -
Object.assign():
Object.assign({}, oldObj),同样只处理第一层,且不拷贝原型链和不可枚举属性 - Array.prototype.slice() / concat():对数组有效,但遇到数组内含对象时,内部对象仍是浅拷贝
例如:const a = { x: 1, y: { z: 2 } }; const b = {...a}; b.y.z = 99; console.log(a.y.z); // 输出 99 —— 因为 b.y 和 a.y 指向同一个对象。
立即学习“Java免费学习笔记(深入)”;
深拷贝:逐层创建新内存空间
深拷贝需遍历原对象的每一层结构,对每个引用类型(对象、数组、Date、RegExp等)都新建实例,并递归处理其属性,确保最终所有嵌套数据在内存中完全隔离。
典型实现路径:
-
JSON 方法(局限大):
JSON.parse(JSON.stringify(obj)),快但丢数据:函数、undefined、Symbol、BigInt、循环引用、Date(转为字符串)、RegExp 等均不支持 -
结构化克隆(现代推荐):
structuredClone(obj)(Chrome 98+、Node.js 17.0+),原生支持 Map、Set、Date、RegExp、ArrayBuffer 及循环引用,是目前最可靠的标准方案 -
手写递归函数:需判断类型(用
Object.prototype.toString.call()或typeof+Array.isArray()),区分基本类型/引用类型/特殊内置对象,维护 WeakMap 解决循环引用问题
为什么循环引用会导致栈溢出?
当对象 A 的某个属性指向自身,或 A → B → A 形成闭环时,朴素递归深拷贝会无限深入,反复访问同一对象,最终耗尽调用栈。解决方法是在递归前用 WeakMap 缓存已拷贝的对象对(原始对象 → 新对象),遇到重复引用时直接返回缓存结果,跳过重复处理。
实际开发中怎么选?
优先使用 structuredClone(),兼容性不足时按需降级:简单纯数据用 JSON 方法;复杂场景(如需兼容老环境 + 支持函数/undefined)再引入 Lodash 的 _.cloneDeep() 或自研带循环检测的版本。切记:没有银弹,深拷贝永远有成本,能用浅拷贝+局部更新就别全量深拷。










