javascript如何实现深拷贝_有哪些方法可以避免引用问题?

发布时间 - 2025-12-30 00:00:00    点击率:
JavaScript深拷贝需创建完全独立副本,避免引用问题;JSON方法简单但有类型限制;structuredClone是现代推荐方案;手写递归可定制但需处理循环引用等细节;Lodash的cloneDeep最全面可靠。

JavaScript 实现深拷贝的核心目标是:创建一个与原对象完全独立的新对象,所有嵌套的属性(包括对象、数组、日期、正则等)都重新分配内存,修改副本不会影响原始数据。引用问题本质上是浅拷贝导致的——只复制了引用地址,而非实际值。

JSON.parse(JSON.stringify()) —— 简单但有局限

这是最常用的一行式方案,适合纯数据对象(仅含字符串、数字、布尔、null、数组、普通对象):

const original = { a: 1, b: { c: 2 } };
const copy = JSON.parse(JSON.stringify(original));

⚠️ 注意限制:

  • 会丢失函数、undefined、Symbol、BigInt、Date、RegExp、Map、Set、Promise 等类型(序列化时被忽略或转为 null)
  • 无法处理循环引用,直接报错 TypeError: Converting circular structure to JSON
  • Date 对象变成字符串,RegExp 变成空对象

structuredClone() —— 现代浏览器推荐方案

Chrome 98+、Firefox 94+、Edge 98+ 支持,能正确处理 Map、Set、Date、RegExp、ArrayBuffer、TypedArray、Error、Blob 等,并支持循环引用:

const original = { date: new Date(), regex: /abc/g, map: new Map([['key', 'value']]) };
const copy = structuredClone(original);

✅ 优点:原生、安全、语义清晰、性能较好
❌ 缺点:IE 不支持,部分 Node.js 版本(v17.0+ 启用 --experimental-structured-cloning)才可用

手写递归深拷贝 —— 灵活可控,适合学习和定制

通过递归判断类型,分别处理基本类型、引用类型、特殊对象:

function deepClone(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);

  const clone = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      clone[key] = deepClone(obj[key]);
    }
  }
  return clone;
}

? 关键点:

  • 必须检查 null(typeof null === 'object' 是 JS 历史 bug)
  • Array.isArray() 判断数组,避免用 instanceof 在跨 iframe 场景失效
  • 需单独处理 Date、RegExp、Map、Set 等,否则会退化为普通对象
  • 要支持循环引用?需额外维护一个 WeakMap 记录已拷贝的对象对

使用成熟库 —— 快速可靠,减少重复造轮子

Lodash 的 _.cloneDeep() 是最广泛使用的方案:

import { cloneDeep } from 'lodash-es';
const copy = cloneDeep(original);

✅ 支持几乎所有 JS 内置类型、循环引用、自定义类实例(可配置)
✅ 经过大量生产环境验证,边界 case 处理完善
⚠️ 注意:体积略大(可按需引入),Tree-shaking 友好(用 lodash-es)

避免引用问题的本质,不是选哪个方法,而是明确你的数据结构和运行环境。简单 JSON 数据用 JSON 方法;现代浏览器项目优先 structuredClone;需要兼容老环境或高度定制就手写或用 Lodash。不复杂但容易忽略细节。


# javascript  # java  # js  # node.js  # json  # node  # 浏览器  # edge  # red 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  laravel怎么使用数据库工厂(Factory)生成带有关联模型的数据_laravel Factory生成关联数据方法  零基础网站服务器架设实战:轻量应用与域名解析配置指南  Laravel DB事务怎么使用_Laravel数据库事务回滚操作  php静态变量怎么调试_php静态变量作用域调试技巧【解答】  深入理解Android中的xmlns:tools属性  实例解析angularjs的filter过滤器  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)  如何登录建站主机?访问步骤全解析  百度输入法ai面板怎么关 百度输入法ai面板隐藏技巧  Laravel怎么写单元测试_PHPUnit在Laravel项目中的基础测试入门  ,交易猫的商品怎么发布到网站上去?  北京网站制作的公司有哪些,北京白云观官方网站?  javascript读取文本节点方法小结  深圳网站制作的公司有哪些,dido官方网站?  ChatGPT回答中断怎么办 引导AI继续输出完整内容的方法  Java Adapter 适配器模式(类适配器,对象适配器)优缺点对比  JavaScript如何实现类型判断_typeof和instanceof有什么区别  Laravel如何处理表单验证?(Requests代码示例)  WordPress 子目录安装中正确处理脚本路径的完整指南  深圳网站制作平台,深圳市做网站好的公司有哪些?  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】  Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南  Laravel如何使用Service Container和依赖注入?(代码示例)  iOS正则表达式验证手机号、邮箱、身份证号等  Laravel Session怎么存储_Laravel Session驱动配置详解  Laravel如何与Pusher实现实时通信?(WebSocket示例)  如何基于云服务器快速搭建个人网站?  jQuery validate插件功能与用法详解  Laravel如何实现数据库事务?(DB Facade示例)  如何在阿里云高效完成企业建站全流程?  Laravel storage目录权限问题_Laravel文件写入权限设置  如何注册花生壳免费域名并搭建个人网站?  微博html5版本怎么弄发超话_超话进入入口及发帖格式要求【教程】  Laravel如何创建自定义Artisan命令?(代码示例)  Laravel怎么实现验证码(Captcha)功能  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】  Win11怎么关闭资讯和兴趣_Windows11任务栏设置隐藏小组件  如何快速辨别茅台真假?关键步骤解析  php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】  Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】  Laravel如何处理JSON字段的查询和更新_Laravel JSON列操作与查询技巧  Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  谷歌浏览器下载文件时中断怎么办 Google Chrome下载管理修复  javascript基于原型链的继承及call和apply函数用法分析  PythonWeb开发入门教程_Flask快速构建Web应用