网站首页 > 技术文章 正文
我用租房合同的比喻帮你彻底理解这个问题
一、生活化解释(租房合同版)
1. 浅拷贝 - 二房东转租
// 原始租房合同
const originalContract = {
address: "杭州西湖101室",
items: ["空调", "沙发"], // 共用家具
landlord: { name: "王阿姨" } // 共用房东信息
};
// 二房东做浅拷贝转租
const shallowCopy = { ...originalContract };
shallowCopy.address = "杭州西湖101室(隔断间)"; // 修改自己的地址
shallowCopy.items.push("洗衣机"); // 实际修改了原始合同的家具
现象:原始合同的items数组被修改,所有租客共享同一份家具清单
2. 深拷贝 - 重新签订合同
// 使用深拷贝生成新合同
function deepClone(obj) { /* 稍后实现 */ }
const newContract = deepClone(originalContract);
newContract.items.push("电视机"); // 只影响新合同
结果:新旧合同完全独立,互不影响
二、代码案例对比
浅拷贝实现方式
// 案例对象
const school = {
name: "浙江大学",
departments: ["计算机系", "电子系"],
info: { location: "北京" }
};
// 方法1:展开运算符
const shallowCopy1 = { ...school };
// 方法2:Object.assign
const shallowCopy2 = Object.assign({}, school);
// 测试修改
shallowCopy1.departments.push("数学系");
console.log(school.departments); // ["计算机系", "电子系", "数学系"]
三、手写深拷贝(详细注释版)
function deepClone(target, map = new WeakMap()) {
// 基本类型直接返回(终止递归的条件)
if (typeof target !== 'object' || target === null) {
return target;
}
// 处理循环引用:如果已经拷贝过该对象,直接返回存储的副本
if (map.has(target)) {
return map.get(target);
}
// 处理特殊对象类型
const constructor = target.constructor;
// Date类型:new Date(value)
if (target instanceof Date) {
return new Date(target);
}
// RegExp类型:new RegExp(source, flags)
if (target instanceof RegExp) {
return new RegExp(target.source, target.flags);
}
// 创建新容器(数组/对象)
const clone = Array.isArray(target) ? [] : {};
// 记录当前对象与拷贝对象的映射关系(解决循环引用)
map.set(target, clone);
// 递归拷贝所有属性
for (let key in target) {
// 只拷贝对象自身的属性(不拷贝原型链上的属性)
if (target.hasOwnProperty(key)) {
clone[key] = deepClone(target[key], map);
}
}
return clone;
}
测试用例
const original = {
name: "测试对象",
features: ["嵌套", { data: "结构" }],
created: new Date(),
regex: /abc/gi,
circular: null // 准备设置循环引用
};
// 设置循环引用
original.circular = original;
// 执行深拷贝
const cloned = deepClone(original);
// 修改拷贝对象
cloned.features[1].data = "修改后的数据";
console.log(original.features[1].data); // 仍然是"结构"
console.log(cloned.circular === cloned); // true(保持循环引用结构)
四、核心区别分析
对比维度 浅拷贝 深拷贝 复制层级 只复制第一层属性 递归复制所有嵌套层级 内存关系 嵌套对象共享内存地址 所有层级都创建新内存空间 修改影响 修改嵌套属性会影响原对象 完全独立,互不影响 性能消耗 快(O(n)) 慢(O(n^2)) 适用场景 简单数据结构的快速复制 需要完全隔离的复杂对象 处理循环引用 无法处理 通过WeakMap记录映射关系 特殊对象处理 直接复制引用 需要特殊处理Date/RegExp等类型
五、开发中的经典应用场景
需要浅拷贝的场景
// 场景:合并默认配置
const defaultConfig = { timeout: 3000, retry: 3 };
const userConfig = { timeout: 5000 };
// 正确做法:浅拷贝合并
const finalConfig = { ...defaultConfig, ...userConfig };
// { timeout: 5000, retry: 3 }
必须用深拷贝的场景
// 场景:保存游戏进度
const currentGameState = {
player: { level: 5, items: ["剑", "盾"] },
enemies: [{ type: "orc" }, { type: "dragon" }]
};
// 正确做法:深拷贝存档
const savedGame = deepClone(currentGameState);
// 修改当前游戏状态不会影响存档
currentGameState.player.level = 6;
console.log(savedGame.player.level); // 仍然是5
六、如何选择拷贝方式?
- 优先考虑浅拷贝:
- 当数据没有嵌套结构时
- 需要高性能处理的简单数据
- 明确知道只需要修改第一层属性
- 必须使用深拷贝:
- 处理来自外部的数据(防止数据污染)
- 需要持久化存储的状态
- 在状态管理(如Redux)中修改嵌套状态
- 处理包含多个嵌套层级的配置对象
建议:当不确定数据结构时,使用深拷贝更安全!但要注意对特殊类型(如函数、DOM元素)的处理需要额外逻辑。
猜你喜欢
- 2025-05-27 WEB前端技术-WEB进阶及学习路径
- 2025-05-27 美国 Ketch 推出业内首款前端数据地图 Data Sentry
- 2025-05-27 WEB前端系列-WEB基础技术栈包括哪些
- 2025-05-27 WEB前端技术-WEB主流框架及开发工具
- 2024-09-25 火山引擎数据调度实例的 DAG 优化方案
- 2024-09-25 数据质量动态探查及相关前端实现 数据质量监控如何实现
- 2024-09-25 除了骁龙X60基带芯片,高通最新推出射频前端ultraSAW滤波器技术
- 2024-09-25 栗子前端技术周刊第 45 期 - Rspack 1.0、Nuxt 3.13、Deno 1.46...
- 2024-09-25 Remotion:使用前端技术开发视频 前端开发的步骤
- 2024-09-25 栗子前端技术周刊第 46 期 - Vue 3.5、Node.js v22.8、Astro 4.15...
你 发表评论:
欢迎- 496℃几个Oracle空值处理函数 oracle处理null值的函数
- 492℃Oracle分析函数之Lag和Lead()使用
- 491℃Oracle数据库的单、多行函数 oracle执行多个sql语句
- 478℃0497-如何将Kerberos的CDH6.1从Oracle JDK 1.8迁移至OpenJDK 1.8
- 470℃Oracle 12c PDB迁移(一) oracle迁移到oceanbase
- 466℃【数据统计分析】详解Oracle分组函数之CUBE
- 450℃Oracle有哪些常见的函数? oracle中常用的函数
- 445℃最佳实践 | 提效 47 倍,制造业生产 Oracle 迁移替换
- 最近发表
-
- Spring Boot跨域难题终结者:3种方案,从此告别CORS噩梦!
- 京东大佬问我,SpringBoot为什么会出现跨域问题?如何解决?
- 在 Spring Boot3 中轻松解决接口跨域访问问题
- 最常见五种跨域解决方案(常见跨域及其解决方案)
- Java Web开发中优雅应对跨域问题(java跨域问题解决办法)
- Spring Boot解决跨域最全指南:从入门到放弃?不,到根治!
- Spring Boot跨域问题终极解决方案:3种方案彻底告别CORS错误
- Spring Cloud 轻松解决跨域,别再乱用了
- Github 太狠了,居然把 "master" 干掉了
- IntelliJ IDEA 调试 Java 8,实在太香了
- 标签列表
-
- 前端设计模式 (75)
- 前端性能优化 (51)
- 前端模板 (66)
- 前端跨域 (52)
- 前端缓存 (63)
- 前端react (48)
- 前端aes加密 (58)
- 前端脚手架 (56)
- 前端md5加密 (54)
- 前端富文本编辑器 (47)
- 前端路由 (55)
- 前端数组 (65)
- 前端定时器 (47)
- Oracle RAC (73)
- oracle恢复 (76)
- oracle 删除表 (48)
- oracle 用户名 (74)
- oracle 工具 (55)
- oracle 内存 (50)
- oracle 导出表 (57)
- oracle 中文 (51)
- oracle链接 (47)
- oracle的函数 (57)
- 前端调试 (52)
- 前端登录页面 (48)
本文暂时没有评论,来添加一个吧(●'◡'●)