如何在 JavaScript 中为嵌套对象创建深度克隆并存入 Map

1次阅读

如何在 JavaScript 中为嵌套对象创建深度克隆并存入 Map

本文详解如何对含嵌套结构的 javaScript 对象执行真正意义上的深度克隆,并将其安全存入 map 实例,避免引用共享问题;涵盖 jsON.parse(json.stringify())、结构化克隆(structuredClone)及第三方方案的适用场景与关键限制。

本文详解如何对含嵌套结构的 javascript 对象执行真正意义上的深度克隆,并将其安全存入 map 实例,避免引用共享问题;涵盖 `json.parse(json.stringify())`、结构化克隆(`structuredclone`)及第三方方案的适用场景与关键限制。

javascript 中,将一个嵌套对象(如 user)存入 Map 时,若仅做浅拷贝(例如用 Object.assign({}, user)),其嵌套属性(如 address)仍会共享原始引用——修改 map.get(“David”).address.city 将意外影响原对象。因此,真正的深度克隆(deep clone)是保障数据隔离的必要步骤

✅ 推荐方案:使用 structuredClone()(现代浏览器 & Node.js 17.0+)

structuredClone() 是 ecmascript 标准原生 API,支持大多数常见类型(Object、Arraydateregexp、Map、Set、TypedArray 等),且能正确处理循环引用(而 JSON 方法无法):

let user = { name: "David", age: "23", address: { city: "Toronto", country: "Canada" } }; let map = new Map();  // ✅ 安全、标准、推荐的深度克隆方式 const deepClonedUser = structuredClone(user); map.set("David", deepClonedUser);  // 验证:修改克隆体不会影响原始对象 deepClonedUser.address.city = "Vancouver"; console.log(user.address.city); // "Toronto" —— 未被修改 ✅

⚠️ 注意:structuredClone 不支持函数、undefinedsymbolpromiseErrordom 节点。若对象含此类值,调用将抛出 DataCloneError。

⚠️ 替代方案:JSON.parse(JSON.stringify())(兼容性高,但有严重限制)

该方法适用于纯 JSON 可序列化的对象(即只含字符串、数字、布尔值、NULL、普通对象和数组):

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

const deepClonedUser = JSON.parse(JSON.stringify(user)); map.set("David", deepClonedUser);

局限性必须牢记:

  • 丢失 Date(变为字符串)、RegExp(变为空对象)、undefined、function、Symbol;
  • 丢弃原型链与构造器信息(结果始终是 plain object);
  • 无法处理循环引用(直接报错 TypeError: Converting circular structure to JSON);
  • BigInt 会抛错(TypeError: Do not know how to serialize a BigInt)。

❌ 不适用方案:Object.assign() 或展开运算符(仅浅克隆)

以下写法不是深度克隆,address 仍为共享引用:

// ❌ 危险!address 对象未被复制 const shallowClone = { ...user }; // 或 Object.assign({}, user) map.set("David", shallowClone); shallowClone.address.city = "Ottawa"; console.log(user.address.city); // "Ottawa" —— 原对象被意外修改!

? 进阶建议:Map 键名设计需规避业务歧义

答案中提到的关键提醒值得强调:map.set(“David”, …) 以姓名为键存在逻辑风险——多名用户同名时将发生覆盖。更健壮的做法是使用唯一 ID(如 _id 或 userId)作为 Map 的 key:

let users = [   { userId: "usr_001", name: "David", address: { city: "Toronto" } },   { userId: "usr_002", name: "David", address: { city: "Montreal" } } ];  const userMap = new Map(); users.forEach(u => {   userMap.set(u.userId, structuredClone(u)); // ✅ 深度克隆 + 唯一键 });

✅ 总结:选择策略一览

方案 兼容性 支持循环引用 支持函数/Symbol/Date 推荐场景
structuredClone() ✅ Node.js ≥17 / chrome ≥98 / firefox ≥94 ❌(除 Date 外多数不支持) 现代环境首选,安全高效
JSON.parse(JSON.stringify()) ✅ 所有环境 ❌(Date 变字符串等) 快速原型、纯数据对象、无特殊类型
Lodash _.cloneDeep() ✅(需引入) ✅(完整支持) 项目已用 Lodash,需最大兼容性
自定义递归克隆 ⚙️ 可控 ✅(需手动实现) ✅(可定制) 特殊需求(如过滤字段、日志追踪)

最终实践口诀:优先用 structuredClone();若需支持旧环境或复杂类型,选用成熟库(如 Lodash);永远避免用浅拷贝处理嵌套对象存入 Map 的场景。

text=ZqhQzanResources