javascript中如何进行深拷贝和浅拷贝?_如何避免对象拷贝带来的引用问题?【教程】

发布时间 - 2026-01-21 00:00:00    点击率:
JavaScript中无自动深拷贝,赋值默认为浅拷贝;浅拷贝仅复制顶层属性,引用类型仍共享内存;JSON方法有诸多限制;可靠方案是structuredClone()或lodash.cloneDeep()。

JavaScript 中没有“自动深拷贝”,所有对象赋值默认都是浅拷贝;想避免引用问题,必须显式选择合适方式处理嵌套结构。

什么是浅拷贝?Object.assign() 和展开运算符 {...obj} 都只拷贝第一层

浅拷贝只复制对象的顶层属性值。如果属性是引用类型(比如数组、对象、Date、RegExp),拷贝后新旧对象仍共享该引用。

常见错误现象:obj2.name = "new" 不影响 obj1.name,但 obj2.items.push(1) 会同步出现在 obj1.items 中。

  • Object.assign({}, obj):不处理原型链、不拷贝 symbol 属性、忽略不可枚举属性
  • {...obj}:同上,且无法处理函数、undefined、null 作为属性值时的行为差异
  • 两者都无法处理循环引用,遇到会报错或静默失败

JSON 方法做深拷贝的限制:JSON.parse(JSON.stringify(obj)) 看似简单,实则脆弱

这是最常被误用的“深拷贝”方案,但它在多种场景下直接失效:

  • 函数、undefinedSymbolBigInt 会被丢弃
  • Date 变成字符串,RegExp 变成空对象 {}
  • 循环引用会抛出 TypeError: Converting circular structure to JSON
  • Map、Set、TypedArray、Error 对象等原生类型无法序列化

仅适用于纯数据对象(POJO),且不含上述任何特殊值——实际业务中极少满足。

真正可靠的深拷贝:用 structuredClone()(现代浏览器)或 lodash.cloneDeep()(兼容性要求高时)

structuredClone() 是原生 API,支持 Map、Set、Date、RegExp、ArrayBuffer、TypedArray、Error、Promise(克隆为 pending 状态)等,并能正确处理循环引用。

  • 支持条件:Chrome 98+Firefox 94+Safari 15.4+;Node.js 17.0+(需启用 --experimental-structured-cloning,18.10+ 默认开启)
  • 不支持函数、undefinedSymbolBigInt —— 这是设计使然,不是 bug
  • 示例:const deepCopy = structuredClone(originalObj);

若需支持更老环境或函数/undefined 等值,lodash.cloneDeep() 更稳妥,但它会把 Date、RegExp 等转为普通对象,行为与 structuredClone() 不同,需按需选型。

如何判断是否真需要深拷贝?多数时候你其实只需要“不可变更新”

深拷贝开销大,且容易掩盖设计问题。很多场景下,用函数式更新 + 解构 + 扩展运算符更轻量、更可控:

  • 更新嵌套字段:{ ...state, user: { ...state.user, name: "Alice" } }
  • 更新数组某项:[...items.slice(0, i), newItem, ...items.slice(i + 1)]
  • 配合 React、Redux、Immer 使用时,深拷贝反而是反模式

真正该警

惕的,是那些你以为“只是读取”却意外修改了原始对象的地方——比如把一个 props 对象直接传给第三方库并让它 mutate,或者在 reducer 里用了 push() / sort() 这类原地方法。


# react  # javascript  # java  # js  # node.js  # json  # node  # 浏览器  # safari  # red 


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


相关推荐: 魔毅自助建站系统:模板定制与SEO优化一键生成指南  Laravel如何实现API资源集合?(Resource Collection教程)  js代码实现下拉菜单【推荐】  C#如何调用原生C++ COM对象详解  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  大型企业网站制作流程,做网站需要注册公司吗?  创业网站制作流程,创业网站可靠吗?  如何在阿里云域名上完成建站全流程?  网站制作价目表怎么做,珍爱网婚介费用多少?  焦点电影公司作品,电影焦点结局是什么?  如何在万网主机上快速搭建网站?  Angular 表单中正确绑定输入值以确保提交与验证正常工作  SQL查询语句优化的实用方法总结  Laravel如何自定义分页视图?(Pagination示例)  Laravel模型事件有哪些_Laravel Model Event生命周期详解  免费视频制作网站,更新又快又好的免费电影网站?  微信小程序 HTTPS报错整理常见问题及解决方案  美食网站链接制作教程视频,哪个教做美食的网站比较专业点?  网站优化排名时,需要考虑哪些问题呢?  如何自定义建站之星模板颜色并下载新样式?  今日头条微视频如何找选题 今日头条微视频找选题技巧【指南】  如何快速搭建安全的FTP站点?  如何用花生壳三步快速搭建专属网站?  如何在阿里云通过域名搭建网站?  javascript中的数组方法有哪些_如何利用数组方法简化数据处理  Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲  高性能网站服务器配置指南:安全稳定与高效建站核心方案  网站制作软件免费下载安装,有哪些免费下载的软件网站?  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  php打包exe后无法访问网络共享_共享权限设置方法【教程】  INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】  phpredis提高消息队列的实时性方法(推荐)  Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明  LinuxShell函数封装方法_脚本复用设计思路【教程】  如何用景安虚拟主机手机版绑定域名建站?  详解MySQL数据库的安装与密码配置  如何为不同团队 ID 动态生成多个非值班状态按钮  Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理  Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】  EditPlus中的正则表达式实战(6)  如何在Windows虚拟主机上快速搭建网站?  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  如何在香港服务器上快速搭建免备案网站?  Laravel怎么为数据库表字段添加索引以优化查询  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  Edge浏览器如何截图和滚动截图_微软Edge网页捕获功能使用教程【技巧】  Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】  网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?  利用 Google AI 进行 YouTube 视频 SEO 描述优化  Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势