深拷贝与浅拷贝详解(包含手写深拷贝与浅拷贝实现)

在 JavaScript 中,浅拷贝(Shallow Copy)深拷贝(Deep Copy) 是处理对象复制的两种方式,它们的区别在于是否递归复制对象的嵌套属性。


浅拷贝

特点:只复制对象的第一层属性,嵌套对象仍然是引用(共享内存)。

1. 手写浅拷贝实现

ini 复制代码
function shallowCopy(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj; // 基本类型直接返回
  }
  const copy = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = obj[key]; // 仅复制第一层
    }
  }
  return copy;
}

// 测试
const obj = { a: 1, b: { c: 2 } };
const copy = shallowCopy(obj);
copy.b.c = 3;
console.log(obj.b.c); // 3(原对象也被修改)

2. JS 内置的浅拷贝方法

Object.assign({}, obj)

ini 复制代码
const obj = { a: 1, b: { c: 2 } };
const copy = Object.assign({}, obj);
copy.b.c = 3; // 原对象也被修改

[...array] (数组扩展运算符)

ini 复制代码
const arr = [1, 2, { a: 3 }];
const copy = [...arr];
copy[2].a = 4; // 原数组也被修改

Array.prototype.slice()

ini 复制代码
const arr = [1, 2, { a: 3 }];
const copy = arr.slice();
copy[2].a = 4; // 原数组也被修改

深拷贝

特点:递归复制所有层级的属性,新旧对象完全独立。

1. 手写深拷贝实现

ini 复制代码
function deepCopy(obj, cache = new WeakMap()) {
  if (typeof obj !== 'object' || obj === null) {
    return obj; // 基本类型直接返回
  }
  if (cache.has(obj)) {
    return cache.get(obj); // 避免循环引用
  }
  const copy = Array.isArray(obj) ? [] : {};
  cache.set(obj, copy); // 缓存对象,防止循环引用
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key], cache); // 递归复制
    }
  }
  return copy;
}

// 测试
const obj = { a: 1, b: { c: 2 } };
const copy = deepCopy(obj);
copy.b.c = 3;
console.log(obj.b.c); // 2(原对象未被修改)

2. JS 内置的深拷贝方法

JSON.parse(JSON.stringify(obj)) (最简单但有限制)

ini 复制代码
const obj = { a: 1, b: { c: 2 } };
const copy = JSON.parse(JSON.stringify(obj));
copy.b.c = 3; // 原对象不受影响

缺点

    • 不能复制 FunctionRegExpDateundefinedSymbol 等特殊类型。
    • 不能处理循环引用(如 obj.self = obj)。

structuredClone() (现代浏览器支持)

ini 复制代码
const obj = { a: 1, b: { c: 2 } };
const copy = structuredClone(obj); // 深拷贝
copy.b.c = 3; // 原对象不受影响

优点

    • 支持 DateRegExpMapSet 等复杂类型。
    • 能处理循环引用。
      缺点
    • 不能复制函数(Function)。

深拷贝 vs 浅拷贝对比

特性 浅拷贝 深拷贝
复制层级 仅第一层 递归所有层级
内存占用 低(共享嵌套对象) 高(完全独立)
修改影响 原对象可能被修改 原对象不受影响
适用场景 简单对象,无嵌套 复杂对象,需完全独立

如何选择?

  • 浅拷贝 :适用于简单对象,如 { a: 1, b: 2 }(无嵌套)。
  • 深拷贝 :适用于复杂对象,如 { a: 1, b: { c: 2 } }(有嵌套)。

推荐方法

  • 浅拷贝Object.assign()[...arr]
  • 深拷贝structuredClone()(现代浏览器)或手写递归深拷贝。

总结

  • 浅拷贝:仅复制第一层,适用于简单数据。
  • 深拷贝:递归复制所有层级,适用于复杂数据。
  • 结构化克隆structuredClone)是最方便的深拷贝方式,但不支持函数。
相关推荐
荣达几秒前
koa洋葱模型理解
前端·后端·node.js
reembarkation26 分钟前
使用pdfjs-dist 预览pdf,并添加文本层的实现
前端·javascript·pdf
reembarkation28 分钟前
vue-pdf 实现blob数据的预览
javascript·vue.js·pdf
李明卫杭州41 分钟前
JavaScript中的dispatchEvent方法详解
javascript
KenXu41 分钟前
F2C-PTD工具将需求快速转换为代码实践
前端
月阳羊42 分钟前
【硬件-笔试面试题-95】硬件/电子工程师,笔试面试题(知识点:RC电路中的时间常数)
java·经验分享·单片机·嵌入式硬件·面试
给月亮点灯|1 小时前
Vue3基础知识-setup()、ref()和reactive()
前端·javascript·vue.js
芜青1 小时前
【Vue2手录12】单文件组件SFC
前端·javascript·vue.js
冷冷的菜哥1 小时前
react实现无缝轮播组件
前端·react.js·typescript·前端框架·无缝轮播
hrrrrb1 小时前
【Python】字符串
java·前端·python