深拷贝在 JavaScript 中的几种实现方式对比

news2025/3/26 4:34:43

深拷贝在 JavaScript 中的几种实现方式对比

  • 1. JSON 序列化法
  • 2. 结构化克隆(structuredClone)
    • 原理与使用
  • 3. 自定义深拷贝函数
      • 原理与使用
  • 性能对比与选择建议
    • 性能比较
  • 综合建议:
  • 示例代码整合
  • 总结

在开发过程中,我们经常需要对对象进行深拷贝,以便创建一个数据的完全独立副本,避免不小心修改原始数据。常见的深拷贝方法有以下几种:
• JSON 序列化法(JSON.stringify/JSON.parse)
• 结构化克隆(structuredClone)
• 自定义深拷贝函数

下面将详细介绍每种方法,并讨论它们在效率和适用场景上的不同。

1. JSON 序列化法

原理与使用
通过 JSON.stringify() 将对象转为 JSON 字符串,再利用 JSON.parse() 还原为新对象。例如:

const deepCopyJson = (obj) => {
  return JSON.parse(JSON.stringify(obj));
};

优点:
• 实现简单,代码少。
• 对于简单对象(不包含函数、undefined、Symbol、循环引用等)非常有效。

缺点:
• 无法处理特殊数据类型:例如 Date、RegExp、Map、Set、undefined、Infinity 等会丢失或转换不正确。
• 当对象数据量较大时,序列化和反序列化过程可能比较耗时。
• 对于包含循环引用的对象会抛错。

适用场景:
加粗样式 • 对象结构简单,数据格式固定时(例如配置数据或简单的 JSON 数据)。

2. 结构化克隆(structuredClone)

原理与使用

现代浏览器提供了原生的 structuredClone() 方法,利用浏览器内部优化的结构化克隆算法,能够高效地复制多种复杂数据结构。使用示例:

if (typeof structuredClone === 'function') {
  const newObj = structuredClone(obj);
}

优点:
• 原生支持,效率较高,尤其适用于大型或复杂对象。
• 能够处理更多类型的数据:如 Map、Set、ArrayBuffer、Date 等。
• 内部实现针对循环引用也能较好地处理。

缺点:
• 浏览器兼容性需要注意,老旧环境可能不支持。
• 对于小对象,可能没有明显优势,有时反而比 JSON 方法稍慢(不过整体差异不大)。

适用场景:
• 对象结构复杂或包含特殊数据类型时;
• 对性能有较高要求且运行环境支持该 API 时。

3. 自定义深拷贝函数

原理与使用

在无法使用 JSON 或 structuredClone 的情况下,可以手动编写递归函数来深度拷贝对象。下面是一个简单的实现:

const deepCopy = (item) => {
  if (item === null || typeof item !== 'object') {
    return item;
  }
  
  if (Array.isArray(item)) {
    return item.map(deepCopy);
  }
  
  const result = {};
  for (const key in item) {
    if (Object.prototype.hasOwnProperty.call(item, key)) {
      result[key] = deepCopy(item[key]);
    }
  }
  return result;
};

const newObj = deepCopy(obj);

优点:
• 灵活性高,可以根据需要扩展以处理更多特殊情况。
• 不依赖环境提供的 API,兼容性好。

缺点:
• 需要手动处理各种边界情况,代码实现和维护较复杂。
• 性能上通常不及浏览器原生实现的 structuredClone。

适用场景:
• 对兼容性有要求的项目或需要定制拷贝逻辑的场景;
• 数据结构较简单,且不频繁调用时。

性能对比与选择建议

性能比较

  • 小型对象:
    JSON 方法通常性能较好,因为序列化过程开销较低,且实现简单。
  • 复杂对象:
    对于包含特殊数据类型或嵌套层次较深的对象,structuredClone 通常表现更优,因为它是浏览器内部实现的,并针对复杂场景做了优化。
  • 自定义函数:
    一般来说,自定义递归实现的性能不及结构化克隆,但可以针对具体需求进行优化。

综合建议:

  1. 优先选择 JSON 方法:当你确定对象数据格式简单,并且不会包含无法序列化的内容时。
  2. 考虑 structuredClone:如果运行环境支持且对象较大或结构复杂,使用 structuredClone() 更能保证数据完整性和性能。
  3. 自定义深拷贝:当需要对数据进行特殊处理或兼容不支持 structuredClone 的环境时,可以采用自定义函数,但要注意性能优化和代码健壮性。

示例代码整合

下面给出一个综合示例,根据对象大小自动选择拷贝方式,并在异常时捕获错误:

function efficientDeepCopy(obj) {
  try {
    if (!obj) return {};

    // 对于小型对象,使用 JSON 方法可能更快
    if (JSON.stringify(obj).length < 10000) {
      return JSON.parse(JSON.stringify(obj));
    }
    // 使用结构化克隆(如果可用)
    if (typeof structuredClone === 'function') {
      return structuredClone(obj);
    }

    // 自定义深拷贝函数,处理常见数据类型
    const deepCopy = (item) => {
      if (item === null || typeof item !== 'object') {
        return item;
      }
      if (Array.isArray(item)) {
        return item.map(deepCopy);
      }
      const result = {};
      for (const key in item) {
        if (Object.prototype.hasOwnProperty.call(item, key)) {
          result[key] = deepCopy(item[key]);
        }
      }
      return result;
    };

    return deepCopy(obj);
  } catch (error) {
    console.error('efficientDeepCopy error:', error);
    return {};
  }
}

在这个示例中,根据对象序列化后的长度来判断是否使用 JSON 方法;如果对象较大且环境支持 structuredClone,则优先使用它;否则回退到自定义深拷贝函数。

总结

  • JSON 方法:适用于简单数据,性能好,但局限性明显。
  • structuredClone:适用于复杂和大型对象,兼容性需要关注,但总体性能较高。
  • 自定义深拷贝:灵活但复杂,一般作为最后的备用方案。

通过对比,可以根据项目的具体需求和对象的特点,选择最合适的深拷贝方式,从而在性能与功能之间取得平衡。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2320954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实验11 机器学习-贝叶斯分类器

实验11 机器学习-贝叶斯分类器 一、实验目的 &#xff08;1&#xff09;理解并熟悉贝叶斯分类器的思想和原理&#xff1b; &#xff08;2&#xff09;熟悉贝叶斯分类器的数学推导过程&#xff1b; &#xff08;3&#xff09;能运用贝叶斯分类器解决实际问题并体会算法的效果&a…

OpenHarmony子系统开发 - 电池管理(二)

OpenHarmony子系统开发 - 电池管理&#xff08;二&#xff09; 五、充电限流限压定制开发指导 概述 简介 OpenHarmony默认提供了充电限流限压的特性。在对终端设备进行充电时&#xff0c;由于环境影响&#xff0c;可能会导致电池温度过高&#xff0c;因此需要对充电电流或电…

hive 数据简介

Hive介绍 1&#xff09;Hive简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;用于结构化数据的查询、分析和汇总。Hive提供类SQL查询功能&#xff0c;它将SQL转换为MapReduce程序。 Hive不支持OLTP&#xff0c;Hive无法提供实时查询。 2&#xff09;Hive在大数据生态环境…

Win32桌面编程:ACLUI.DLL,EditSecurity(IntPtr hwndOwner, ISecurityInformation psi)

在Windows编程中&#xff0c;我们通常需要借助通用对话框的力量&#xff0c;今天我们就聊一下“安全属性表”通用对话框的使用心得。 当我们调用EditSecurity函数时&#xff1a; 1.EditSecurity将调用ISecurityInformation中的GetObjectInformation函数 在编写 ISecurityInf…

数据分析异步进阶:aiohttp与Asyncio性能提升

一、时间轴呈现方案进程 2023-04-01&#xff1a;需求确认 确定目标&#xff1a;使用aiohttp与Asyncio提升采集性能&#xff0c;目标采集今日头条网站的新闻数据&#xff08;标题、内容、时间等&#xff09;。同时要求在程序中加入代理IP、Cookie和UserAgent的设置&#xff0c;…

《AI大模型趣味实战 》第8集:多端适配 个人新闻头条 基于大模型和RSS聚合打造个人新闻电台(Flask WEB版) 2

《AI大模型趣味实战 》第8集&#xff1a;多端适配 个人新闻头条 基于大模型和RSS聚合打造个人新闻电台(Flask WEB版) 2 摘要 本文末尾介绍了如何实现新闻智能体的方法。在信息爆炸的时代&#xff0c;如何高效获取和筛选感兴趣的新闻内容成为一个现实问题。本文将带领读者通过P…

低配电脑畅玩《怪物猎人:荒野》,ToDesk云电脑优化从30帧到144帧?

《怪物猎人&#xff1a;荒野&#xff08;Monster Hunter Wilds&#xff09;》自2025年正式发售以来已取得相当亮眼的成绩&#xff0c;仅用三天时间便轻松突破800万销量&#xff0c;目前顺利蝉联周榜冠军&#xff1b;凭借着开放世界的宏大场景和丰富的狩猎玩法&#xff0c;该游戏…

【js逆向入门】图灵爬虫练习平台 第九题

地址&#xff1a;aHR0cHM6Ly9zdHUudHVsaW5ncHl0b24uY24vcHJvYmxlbS1kZXRhaWwvOS8 f12进入了debugger&#xff0c;右击选择一律不在此处暂停&#xff0c; 点击继续执行 查看请求信息 查看载荷&#xff0c;2个加密参数&#xff0c;m和tt 查看启动器&#xff0c;打上断点 进来 往…

NET6 WebApi第5讲:中间件(源码理解,俄罗斯套娃怎么来的?);Web 服务器 (Nginx / IIS / Kestrel)、WSL、SSL/TSL

一、NET6的启动流程 区别&#xff1a; .NET6 WebApi第1讲&#xff1a;VSCode开发.NET项目、区别.NET5框架【两个框架启动流程详解】_vscode webapi-CSDN博客 2、WebApplicationBuilder&#xff1a;是NET6引入的一个类&#xff0c;是建造者模式的典型应用 1>建造者模式的…

Nginx及前端部署全流程:初始化配置到生产环境部署(附Nginx常用命令)

nginx&前端从初始化配置到部署&#xff08;xshell&#xff09; 前言下载nginx前端打包与创建具体文件夹路径配置nginx.nginx.conf文件配置项内容 配置nginx.service文件配置项内容 启动nginx常用nginx命令 前言 目标&#xff1a;在xshell中部署前端包。 第一步&#xff1a…

python 实现一个简单的window 任务管理器

import tkinter as tk from tkinter import ttk import psutil# 运行此代码前&#xff0c;请确保已经安装了 psutil 库&#xff0c;可以使用 pip install psutil 进行安装。 # 由于获取进程信息可能会受到权限限制&#xff0c;某些进程的信息可能无法获取&#xff0c;代码中已经…

【xiaozhi赎回之路-2:语音可以自己配置就是用GPT本地API】

固件作用 打通了网络和硬件的沟通 修改固件实现【改变连接到小智服务器的】 回答逻辑LLM自定义 自定义了Coze&#xff08;比较高级&#xff0c;自定义程度比较高&#xff0c;包括知识库&#xff0c;虚拟脚色-恋人-雅思老师-娃娃玩具{可能需要使用显卡对开源模型进行微调-产…

WX小程序

下载 package com.sky.utils;import com.alibaba.fastjson.JSONObject; import org.apache.http.NameValuePair; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.Cl…

Spring boot 3.4 后 SDK 升级,暨 UI API/MCP 计划

PS 写这篇文章后看到 A Deep Dive Into MCP and the Future of AI Tooling | Andreessen HorowitzWe explore what MCP is, how it changes the way AI interacts with tools, what developers are already building, and the challenges that still need solving. https://a1…

Linux下JDK1.8安装配置

目录 1.下载完上传到Linux系统中 2.解压JDK压缩包 3.配置JDK环境变量 4.设置环境变量生效 5.查看环境变量是否配置成功 官网下载地址:Java Downloads | Oracle 1.下载完上传到Linux系统中 2.解压JDK压缩包 tar -zxvf jdk-8u151-linux-x64.tar.gz -C /usr/local (解压…

Python OCR文本识别详细步骤及代码示例

光学字符识别&#xff08;OCR&#xff09;是将图像中的文字转换为可编辑文本的技术。在Python中&#xff0c;我们可以利用多种库实现OCR功能。本文将详细介绍使用Tesseract和EasyOCR进行文本识别的步骤&#xff0c;并提供完整的代码示例。 一、OCR简介 OCR&#xff08;Optical…

Linux固定IP方法(RedHat+Net模式)

1、查看当前网关 ip route | grep default 2、配置静态IP 双击重启 3、验证

210、【图论】课程表(Python)

题目 思路 这道题本质上是一个拓扑排序。每次先统计每个点的入度个数、然后再统计点与点之间的邻接关系&#xff0c;找到入度为0的点作为起始遍历点。之后每遍历到这个点之后&#xff0c;就把这个点后续的邻接关系边的点入度减去一。当某个点入度为0时&#xff0c;继续被加入其…

跟着StatQuest学知识07-张量与PyTorch

一、张量tensor 张量重新命名一些数据概念&#xff0c;存储数据以及权重和偏置。 张量还允许与数据相关的数学计算能够相对快速的完成。 通常&#xff0c;张量及其进行的数学计算会通过成为图形处理单元&#xff08;GPUs&#xff09;的特殊芯片来加速。但还有张量处理单元&am…

前端字段名和后端不一致?解锁 JSON 映射的“隐藏规则” !!!

&#x1f680; 前端字段名和后端不一致&#xff1f;解锁 JSON 映射的“隐藏规则” &#x1f31f; 嘿&#xff0c;技术冒险家们&#xff01;&#x1f44b; 今天我们要聊一个开发中常见的“坑”&#xff1a;前端传来的 JSON 参数字段名和后端对象字段名不一致&#xff0c;会发生…