如何在 JavaScript 中实现数组的深度克隆并保持对象引用独立?

14次阅读

如何在 JavaScript 中实现数组的深度克隆并保持对象引用独立?

本文介绍 `structuredclone()` 这一现代原生 api,它能安全、高效地对包含 datemap、set、regexpArraybuffer 等复杂类型的数组执行**深拷贝**,确保新数组与原数组完全隔离,且不丢失数据类型语义。

javaScript 中,浅拷贝(如展开运算符 […a]、slice()、Array.from())仅复制数组第一层引用,内部嵌套的对象、日期、正则等仍共享内存地址——修改副本中的嵌套属性会意外影响原始数据。而 jsON.parse(json.stringify()) 虽可实现深拷贝,却存在严重局限:它会序列化 Date 为字符串、丢弃 undefinedfunctionsymbol、BigInt、RegExp、Map、Set 等不可序列化值,导致数据失真。

所幸,现代浏览器node.js(v17.0+ 默认启用,v18.13+ 稳定支持)已原生提供 structuredClone() ——一个专为结构化克隆算法(Structured Clone Algorithm)设计的标准 API。它不仅能完整保留 Date、RegExp、Map、Set、ArrayBuffer、TypedArray、Error 等内置对象的类型和状态,还能正确处理循环引用(自动避免无限递归),且性能优于手写递归深拷贝。

以下是一个典型示例:

const a = [1, new Date('2023-07-19T10:35:21'), false, {    date: new Date('2023-07-19T10:35:21'),    name: "John Doe",   nested: { id: 42 } }];  const b = structuredClone(a);  // ✅ 完全独立的引用 console.log(a === b);           // false console.log(a[1] === b[1]);     // false(两个 Date 实例不同) console.log(a[3] === b[3]);     // false console.log(a[3].nested === b[3].nested); // false  // ✅ 修改副本不影响原始数据 b[3].date = null; b[3].nested.id = 999;  console.log(a[3].date);        // Date { ... }(未被修改) console.log(a[3].nested.id);   // 42(原始值保持不变) console.log(b[3].date);        // null console.log(b[3].nested.id);   // 999

⚠️ 注意事项

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

  • 兼容性:需检查运行环境支持情况(caniuse.com/structured-clone)。对于不支持的旧环境(如 IE、旧版 safari),可使用 @ungap/structured-clone 等轻量 polyfill。
  • 限制类型:structuredClone() 不支持 function、undefined、Symbol、WeakMap、WeakSet 和 window 对象等非可传输(non-transferable)值——尝试克隆会抛出 DataCloneError。
  • 性能提示:对超大嵌套结构,structuredClone() 仍优于多数手动实现;但若需精细控制(如忽略某些字段或自定义转换逻辑),仍建议封装带策略的深拷贝工具函数。

总结:当目标是「获得一个与原数组内容一致、但所有嵌套对象/值均拥有全新内存引用」时,structuredClone() 是当前最标准、最可靠、最简洁的解决方案。无需自行实现递归逻辑,也无需妥协于 JSON 序列化的类型损失——只需一行代码,即可达成真正意义上的深度克隆。

text=ZqhQzanResources