翼度科技»论坛 编程开发 JavaScript 查看内容

深入探索JavaScript中的structuredClone:现代深拷贝的解密指南

9

主题

9

帖子

27

积分

新手上路

Rank: 1

积分
27
在 JavaScript 中,实现深拷贝的方式有很多种,每种方式都有其优点和缺点。今天介绍一种原生 JavaScript 提供的structuredClone实现深拷贝。
下面列举一些常见的方式,以及它们的代码示例和优缺点:
1. 使用 JSON.parse(JSON.stringify(obj))

代码示例:
  1. function deepClone(obj) {
  2.     return JSON.parse(JSON.stringify(obj));
  3. }
复制代码
优点:简单易行,对于大多数对象类型有效。
缺点:不能复制原型链,对于包含循环引用的对象可能出现问题。比如以下代码:
  1. const calendarEvent = {
  2.   date: new Date()
  3. }
  4. const problematicCopy = JSON.parse(JSON.stringify(calendarEvent))
复制代码
最终得到的 date 不是 Data 对象,而是字符串。
  1. {
  2.     "date": "2024-03-02T03:43:35.890Z"
  3. }
复制代码
这是因为JSON.stringify只能处理基本的对象、数组。任何其他类型都没有按预期处理。例如,日期转换为字符串。Set/Map 只是转换为{}。
  1. const kitchenSink = {
  2.   set: new Set([1, 3, 3]),
  3.   map: new Map([[1, 2]]),
  4.   regex: /foo/,
  5.   deep: { array: [ new File(someBlobData, 'file.txt') ] },
  6.   error: new Error('Hello!')
  7. }
  8. const veryProblematicCopy = JSON.parse(JSON.stringify(kitchenSink))
复制代码
最终得到如下数据:
  1. {
  2.   "set": {},
  3.   "map": {},
  4.   "regex": {},
  5.   "deep": {
  6.     "array": [
  7.       {}
  8.     ]
  9.   },
  10.   "error": {},
  11. }
复制代码
2. 使用递归

代码示例:
  1. function deepClone(obj) {
  2.     if (obj === null || typeof obj !== 'object') {
  3.         return obj;
  4.     }
  5.     let clone = obj.constructor();
  6.     for (let attr in obj) {
  7.         if (obj.hasOwnProperty(attr)) {
  8.             clone[attr] = this.deepClone(obj[attr]);
  9.         }
  10.     }
  11.     return clone;
  12. }
复制代码
优点:对于任何类型的对象都有效,包括循环引用。
缺点:对于大型对象可能会消耗大量内存,并可能导致堆栈溢出。
3. 第三方库,如 lodash 的 _.cloneDeep 方法

代码示例:
  1. const _ = require('lodash');
  2. function deepClone(obj) {
  3.     return _.cloneDeep(obj);
  4. }
复制代码
优点:支持更多类型的对象和库,例如,支持 Proxy 对象。
缺点:会引入依赖导致项目体积增大。

因为这个函数会导致 17.4kb 的依赖引入,如果只是引入 lodash 会更高。
4. 现代深拷贝 structuredClone

在现代浏览器中,可以使用 structuredClone 方法来实现深拷贝,它是一种更高效、更安全的深拷贝方式。
以下是一个示例代码,演示如何使用 structuredClone 进行深拷贝:
  1. const kitchenSink = {
  2.   set: new Set([1, 3, 3]),
  3.   map: new Map([[1, 2]]),
  4.   regex: /foo/,
  5.   deep: { array: [ new File(someBlobData, 'file.txt') ] },
  6.   error: new Error('Hello!')
  7. }
  8. kitchenSink.circular = kitchenSink
  9. const clonedSink = structuredClone(kitchenSink)
复制代码
structuredClone可以做到:

  • 拷贝无限嵌套的对象和数组
  • 拷贝循环引用
  • 拷贝各种各样的 JavaScript 类型,如Date、Set、Map、Error、RegExp、ArrayBuffer、Blob、File、ImageData等
哪些不能拷贝:

  • 函数
  • DOM 节点
  • 属性描述、setter和getter
  • 对象原型链
所支持的完整列表:
Array、ArrayBuffer、Boolean、DataView、Date、Error类型(下面具体列出的类型)、Map、Object,但仅限于普通对象、原始类型,除了symbol(又名number、string、null、undefined、boolean、BigInt)、RegExp、Set、TypedArray
Error 类型:
Error, EvalError, RangeError, ReferenceError , SyntaxError, TypeError, URIError
Web/API 类型:
AudioData, Blob, CryptoKey, DOMException, DOMMatrix, DOMMatrixReadOnly, DOMPoint, DomQuad, DomRect, File, FileList, FileSystemDirectoryHandle, FileSystemFileHandle, FileSystemHandle, ImageBitmap, ImageData, RTCCertificate, VideoFrame
值得庆幸的是 structuredClone 在所有主流浏览器中都受支持,也支持 Node.js 和 Deno。

结语

我们现在终于可以直接使用原生 JavaScript 中的structuredClone能力实现深度拷贝对象。每种方式都有其优缺点,具体使用方式取决于你的需求和目标对象的类型。
更多内容请看:https://mybj123.com/20631.html

来源:https://www.cnblogs.com/mybj123/p/18184995
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具