前端深拷贝的实现方法

2025/3/14
本文详细介绍了前端开发中深拷贝的概念,并阐述了多种实现深拷贝的方法,包括使用 `JSON.parse` 和 `JSON.stringify`、递归实现、`structuredClone`、第三方库(如 Lodash),还讲解了处理特殊类型(如 `Date`、`RegExp` 等)和循环引用的方法,最后给出了不同场景下选择深拷贝方法的建议。
展示深拷贝不同实现方法代码示例的图片,体现特殊类型和循环引用处理示例的图片,对比不同场景适用深拷贝方法的图表图片

在前端开发中,深拷贝(Deep Copy)是指创建一个新对象,并将原对象的所有属性递归地复制到新对象中,使得新对象与原对象完全独立,修改新对象不会影响原对象。实现深拷贝有多种方法,以下是几种常见的实现方式:

1. 使用 JSON.parseJSON.stringify

这是最简单的方法,但有一些局限性(例如不能处理函数、undefinedSymbol、循环引用等)。

function deepCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
}

const original = { a: 1, b: { c: 2 } };
const copied = deepCopy(original);

console.log(copied); // { a: 1, b: { c: 2 } }

2. 递归实现

通过递归遍历对象的属性,逐一复制到新对象中。

function deepCopy(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (Array.isArray(obj)) {
    const arrCopy = [];
    for (let i = 0; i < obj.length; i++) {
      arrCopy[i] = deepCopy(obj[i]);
    }
    return arrCopy;
  }

  const objCopy = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      objCopy[key] = deepCopy(obj[key]);
    }
  }
  return objCopy;
}

const original = { a: 1, b: { c: 2 } };
const copied = deepCopy(original);

console.log(copied); // { a: 1, b: { c: 2 } }

3. 使用 structuredClone

现代浏览器提供了 structuredClone 方法,可以处理大多数数据类型(包括循环引用)。

const original = { a: 1, b: { c: 2 } };
const copied = structuredClone(original);

console.log(copied); // { a: 1, b: { c: 2 } }

4. 使用第三方库(如 Lodash)

Lodash 提供了 _.cloneDeep 方法,可以处理复杂的对象结构。

import _ from 'lodash';

const original = { a: 1, b: { c: 2 } };
const copied = _.cloneDeep(original);

console.log(copied); // { a: 1, b: { c: 2 } }

5. 处理特殊类型(如 DateRegExp 等)

如果需要处理特殊类型(如 DateRegExp 等),可以在递归实现中增加对这些类型的处理。

function deepCopy(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (obj instanceof Date) {
    return new Date(obj);
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  if (Array.isArray(obj)) {
    const arrCopy = [];
    for (let i = 0; i < obj.length; i++) {
      arrCopy[i] = deepCopy(obj[i]);
    }
    return arrCopy;
  }

  const objCopy = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      objCopy[key] = deepCopy(obj[key]);
    }
  }
  return objCopy;
}

const original = { a: 1, b: { c: 2 }, d: new Date() };
const copied = deepCopy(original);

console.log(copied); // { a: 1, b: { c: 2 }, d: Date }

6. 处理循环引用

如果需要处理循环引用,可以使用 WeakMap 来存储已经拷贝过的对象。

function deepCopy(obj, map = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  if (map.has(obj)) {
    return map.get(obj);
  }

  if (obj instanceof Date) {
    return new Date(obj);
  }

  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  if (Array.isArray(obj)) {
    const arrCopy = [];
    map.set(obj, arrCopy);
    for (let i = 0; i < obj.length; i++) {
      arrCopy[i] = deepCopy(obj[i], map);
    }
    return arrCopy;
  }

  const objCopy = {};
  map.set(obj, objCopy);
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      objCopy[key] = deepCopy(obj[key], map);
    }
  }
  return objCopy;
}

const original = { a: 1 };
original.self = original;
const copied = deepCopy(original);

console.log(copied); // { a: 1, self: [Circular] }

总结

  • 简单场景:可以使用 JSON.parse(JSON.stringify(obj))
  • 复杂场景:建议使用递归实现或 structuredClone
  • 特殊类型:需要额外处理 DateRegExp 等类型。
  • 循环引用:使用 WeakMap 来避免无限递归。

根据具体需求选择合适的方法来实现深拷贝。

标签:JavaScript
上次更新:

相关文章

npx完全指南:前端开发必备工具详解 | 20年架构师深度解析

本文由20年前端架构师深入解析npx工具,涵盖其核心功能、优势、高级用法、最佳实践及与npm/yarn的区别比较,帮助开发者掌握这一现代前端开发利器。

·前端开发

Astro 静态站点生成器:构建高性能网站的最佳选择

Astro 是一个专注于构建快速、轻量级网站的静态站点生成器,支持多种前端框架,采用岛屿架构减少 JavaScript 加载,提升性能。

·前端开发

MySQL JSON数据类型支持与使用指南 | 详细解析与示例

本文详细解析了MySQL从5.7版本开始支持的JSON数据类型,包括版本支持、创建JSON字段、插入与查询JSON数据、修改JSON数据、生成JSON、索引优化、性能与应用场景、注意事项及示例全流程。

·后端开发

Weex 跨平台移动开发框架:核心特性与使用指南

Weex 是由阿里巴巴开源的跨平台移动开发框架,支持使用 Vue.js 或 Rax 构建高性能的 iOS、Android 和 Web 应用。本文详细解析了 Weex 的核心特性、架构、工作流程、组件和模块、开发工具、优缺点、应用场景及未来发展。

·前端开发

ECharts 与 DataV 数据可视化工具对比分析 | 选择指南

本文详细对比了 ECharts 和 DataV 两个常用的数据可视化工具,包括它们的设计目标、优缺点、使用场景和技术栈,帮助读者根据具体需求选择合适的工具。

·前端开发

前端部署后通知用户刷新页面的常见方案 | 单页应用更新提示

本文介绍了在前端部署后通知用户刷新页面的几种常见方案,包括WebSocket实时通知、轮询检查版本、Service Worker版本控制、版本号对比、自动刷新、使用框架内置功能以及第三方库。每种方案的优缺点和示例代码均有详细说明。

·前端开发

file-saver:前端文件下载的 JavaScript 库使用指南

file-saver 是一个用于在浏览器端保存文件的 JavaScript 库,支持生成和下载多种文件格式,如文本、JSON、CSV、图片、PDF 等。本文详细介绍其安装、基本用法、兼容性及与其他工具(如 jszip)的结合使用。

·前端开发

MSW(Mock Service Worker):API 模拟工具的核心优势与使用指南

MSW(Mock Service Worker)是一个用于浏览器和 Node.js 的 API 模拟工具,通过 Service Worker 拦截网络请求,支持 REST 和 GraphQL,适用于开发、测试和调试场景。本文详细介绍 MSW 的核心优势、快速上手步骤、高级用法、适用场景及与其他 Mock 工具的对比。

·前端开发

Preact:轻量级 JavaScript 库,React 的高性能替代方案

Preact 是一个轻量级的 JavaScript 库,提供与 React 相似的 API 和开发体验,但体积更小(约 3-4KB,gzip 后)。它专注于高性能和低资源消耗,特别适合对性能敏感或需要快速加载的 Web 应用。

·前端开发

WASI标准与WebAssembly跨平台生态的未来趋势分析 | 技术深度解析

本文深入探讨了WASI(WebAssembly System Interface)标准的背景、意义及其对WebAssembly跨平台生态的影响。文章分析了WASI在服务器端应用、边缘计算和IoT设备中的应用,以及技术栈和工具链的演进,最后展望了WASI对未来前端开发的影响和最佳实践建议。

·前端开发