什么是深拷贝和浅拷贝_在javascript中如何实现

浅拷贝只复制第一层引用,深拷贝递归复制所有层级;Object.assign()和展开运算符是浅拷贝,JSON.stringify()有诸多限制,structuredClone()是现代可靠方案但不支持函数等类型。

浅拷贝只复制第一层引用,深拷贝递归复制所有层级

JavaScript 中对象和数组是引用类型,直接赋值只是复制了内存地址。浅拷贝只断开最外层的引用,内部嵌套的对象/数组仍共享;深拷贝则确保新对象与原对象完全独立,修改任意一层都不会互相影响。

Object.assign() 和展开运算符 ... 是典型浅拷贝

它们只处理对象自身可枚举属性,且仅拷贝第一层:

const a = { x: 1, y: { z: 2 } };
const b = { ...a };
b.y.z = 99;
console.log(a.y.z); // 99 —— 被意外修改
  • Object.assign({}, obj) 不处理 nullundefined 源对象
  • 展开运算符对 MapSetDateRegExp 等无效,会丢失类型和原型
  • 遇到 Symbol 属性时,Object.assign() 会拷贝,但展开运算符不会

JSON.parse(JSON.stringify()) 是有缺陷的“伪深拷贝”

它能处理多层嵌套,但存在多个硬性限制:

const obj = { a: 1, b: () => {}, c: undefined, d: Symbol('x'), e: new Date(), f: /abc/ };
const copy = JSON.parse(JSON.stringify(obj));
// 结果:{ a: 1, e: "2025-01-01T00:00:00.000Z" } —— 其余全丢失
  • 函数、undefinedSymbolBigInt 会被静默丢弃
  • Date 变成字符串,RegExp 变成空对象,Map/Set 变成空对象
  • 循环引用会直接抛出 TypeError: Converting circular structure to JSON
  • 无法保留原型链和不可枚举属性

真正可靠的深拷贝需用 structuredClone() 或手写递归函数

structuredClone() 是现代浏览器(Chrome 98+、Firefox 94+、Safari 16.4+)原生支持的方案,能正确处理 DateRegExpMapSetArrayBuffer 等,且支持循环引用:

const obj = { a: new Date(), b: new Map([[1, 'x']]) };
const copy = structuredClone(obj);
copy.a.setFullYear(2050);
console.log(obj.a.getFullYear()); // 仍是原年份
  • 不支持函数、undefinedSymbolBigInt(同 JSON.stringify 的限制,但明确报错而非静默丢弃)
  • Node.js 17.0+ 需启用 --experimental-structured-cloning 标志,18.15+ 默认启用
  • 若需兼容老环境,手写递归函数必须显式判断 Array.isArray()obj.constructor === Date 等类型,并用 WeakMap 记录已遍历对象以解决循环引用

真正复杂的数据结构深拷贝没有银弹——structuredClone() 覆盖大多数场景,但一旦涉及函数序列化或自定义类实例,就得按需定制逻辑。