javascript深拷贝是什么_怎样实现对象的深度复制?

发布时间 - 2026-01-06 00:00:00    点击率:
深拷贝是创建完全独立的新对象,与原对象内存隔离;Object.assign()等为浅拷贝;JSON.parse(JSON.stringify())最快但限制多;递归实现需WeakMap防循环引用;Lodash的cloneDeep()最稳妥。

深拷贝就是复制出一个完全独立的新对象

JavaScript 中的 Object.assign()、展开运算符 {...obj} 或直接赋值 let b = a 都只是浅拷贝——它们只复制第一层属性,嵌套的对象或数组仍然共享引用。一旦修改嵌套内容,原对象也会被意外改变。深拷贝的目标是让新对象和原对象在内存中彻底隔离,互不影响。

JSON.parse(JSON.stringify()) 最快但限制多

这是最常用的“取巧”方式,适合纯数据对象(只含字符串、数字、布尔、null、数组、普通对象),不支持 DateRegExpundefinedfunctionSymbolBigInt 或循环引用。遇到这些会静默丢失或报错。

const obj = { a: 1, b: { c: 2 } };
const copy = JSON.parse(JSON.stringify(obj));
copy.b.c = 99;
console.log(obj.b.c); // 2 —— 原对象未变
  • undefined 和函数会被忽略
  • Date 变成字符串(如 "2025-01-01T00:00:00.000Z"
  • 循环引用直接抛 TypeError: Converting circular structure to JSON

递归实现能处理函数和 Date,但要小心循环引用

手写深拷贝的核心是:遍历每个属性,对对象/数组递归调用自身,对基本类型直接返回。关键难点在于检测并缓存已访问过的对象,避免无限递归。

function deepClone(obj, map = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (map.has(obj)) return map.get(obj);
  
  const cloned = Array.isArray(obj) ? [] : {};
  map.set(obj, cloned);
  
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      cloned[key] = deepClone(obj[key], map);
    }
  }
  return cloned;
}
  • WeakMap 缓存源对象 → 克隆对象映射,解决循环引用
  • 保留 DateRegExpMapSet 等类型需额外判断分支
  • 无法克隆 function 的作用域或闭包,但函数本身可被复制(因函数是对象,且通常不需要“深”进函数体)

Lodash 的 cloneDeep() 是生产环境最稳妥的选择

它覆盖了几乎所有边界情况:MapSetTypedArrayBufferError、循环引用、不可枚举属性、原型链等。体积稍大,但省去自己踩坑的成本。

立即学习“Java免费学习笔记(深入)”;

import { cloneDeep } from 'lodash-es';
const obj = { date: new Date(), map: new Map([['a', 1]]) };
const copy = cloneDeep(obj);
console.log(copy.date instanceof Date); // true
console.log(copy.map.size); // 1
  • 不依赖全局 JSON,兼容性更好
  • undefinedSymbolBigInt 也能保留(取决于版本)
  • 如果项目已用 Lodash,直接用;否则引入单个函数比手写更可靠
实际项目里,别硬刚“最简实现”。循环引用、稀疏数组、带 getter 的对象、Proxy 实例……这些细节加起来,会让手写深拷贝迅速变得不可维护。真正需要深拷贝的地方,往往也意味着数据结构已经复杂到值得依赖成熟方案。


# javascript  # java  # js  # json  # proxy  # 作用域 


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


相关推荐: Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】  如何在阿里云虚拟服务器快速搭建网站?  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  浏览器如何快速切换搜索引擎_在地址栏使用不同搜索引擎【搜索】  悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤  历史网站制作软件,华为如何找回被删除的网站?  如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程  Laravel怎么调用外部API_Laravel Http Client客户端使用  javascript中的数组方法有哪些_如何利用数组方法简化数据处理  logo在线制作免费网站在线制作好吗,DW网页制作时,如何在网页标题前加上logo?  Laravel Blade模板引擎语法_Laravel Blade布局继承用法  如何在香港免费服务器上快速搭建网站?  如何快速查询网址的建站时间与历史轨迹?  如何续费美橙建站之星域名及服务?  如何快速查询域名建站关键信息?  如何挑选最适合建站的高性能VPS主机?  手机软键盘弹出时影响布局的解决方法  网站建设要注意的标准 促进网站用户好感度!  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  高防服务器租用指南:配置选择与快速部署攻略  Laravel怎么实现验证码功能_Laravel集成验证码库防止机器人注册  Laravel如何创建自定义Artisan命令?(代码示例)  详解jQuery中基本的动画方法  晋江文学城电脑版官网 晋江文学城网页版直接进入  Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境  怎样使用JSON进行数据交换_它有什么限制  googleplay官方入口在哪里_Google Play官方商店快速入口指南  php8.4header发送头信息失败怎么办_php8.4header函数问题解决【解答】  独立制作一个网站多少钱,建立网站需要花多少钱?  如何彻底删除建站之星生成的Banner?  通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】  奇安信“盘古石”团队突破 iOS 26.1 提权  Laravel怎么自定义错误页面_Laravel修改404和500页面模板  阿里云网站搭建费用解析:服务器价格与建站成本优化指南  Android利用动画实现背景逐渐变暗  高性能网站服务器部署指南:稳定运行与安全配置优化方案  Laravel如何使用Eloquent进行子查询  实例解析angularjs的filter过滤器  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  如何获取PHP WAP自助建站系统源码?  Laravel如何发送系统通知?(Notification渠道示例)  如何快速搭建二级域名独立网站?  Laravel怎么防止CSRF攻击_Laravel CSRF保护中间件原理与实践  在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?  敲碗10年!Mac系列传将迎来「触控与联网」双革新  如何在云主机上快速搭建网站?  潮流网站制作头像软件下载,适合母子的网名有哪些?  javascript读取文本节点方法小结  nodejs redis 发布订阅机制封装实现方法及实例代码  Laravel怎么实现API接口鉴权_Laravel Sanctum令牌生成与请求验证【教程】