共计 2562 个字符,预计需要花费 7 分钟才能阅读完成。
在 JavaScript 中,实现深拷贝的形式有很多种,每种形式都有其长处和毛病。明天介绍一种原生 JavaScript 提供的 structuredClone
实现深拷贝。
上面列举一些常见的形式,以及它们的代码示例和优缺点:
1. 应用JSON.parse(JSON.stringify(obj))
代码示例:
function deepClone(obj) {return JSON.parse(JSON.stringify(obj));
}
长处:简单易行,对于大多数对象类型无效。
毛病:不能复制原型链,对于蕴含循环援用的对象可能呈现问题。比方以下代码:
const calendarEvent = {date: new Date()
}
const problematicCopy = JSON.parse(JSON.stringify(calendarEvent))
最终失去的 date 不是 Data 对象,而是字符串。
{"date": "2024-03-02T03:43:35.890Z"}
这是因为 JSON.stringify
只能解决根本的对象、数组。任何其余类型都没有按预期解决。例如,日期转换为字符串。Set/Map 只是转换为{}
。
const kitchenSink = {set: new Set([1, 3, 3]),
map: new Map([[1, 2]]),
regex: /foo/,
deep: {array: [ new File(someBlobData, 'file.txt') ] },
error: new Error('Hello!')
}
const veryProblematicCopy = JSON.parse(JSON.stringify(kitchenSink))
最终失去如下数据:
{"set": {},
"map": {},
"regex": {},
"deep": {
"array": [{}
]
},
"error": {},}
2. 应用递归
代码示例:
function deepClone(obj) {if (obj === null || typeof obj !== 'object') {return obj;}
let clone = obj.constructor();
for (let attr in obj) {if (obj.hasOwnProperty(attr)) {clone[attr] = this.deepClone(obj[attr]);
}
}
return clone;
}
长处:对于任何类型的对象都无效,包含循环援用。
毛病:对于大型对象可能会耗费大量内存,并可能导致堆栈溢出。
3. 第三方库,如 lodash 的 _.cloneDeep
办法
代码示例:
const _ = require('lodash');
function deepClone(obj) {return _.cloneDeep(obj);
}
长处:反对更多类型的对象和库,例如,反对 Proxy 对象。
毛病:会引入依赖导致我的项目体积增大。
因为这个函数会导致 17.4kb 的依赖引入,如果只是引入 lodash 会更高。
4. 古代深拷贝 structuredClone
在古代浏览器中,能够应用 structuredClone
办法来实现深拷贝,它是一种更高效、更平安的深拷贝形式。
以下是一个示例代码,演示如何应用 structuredClone
进行深拷贝:
const kitchenSink = {set: new Set([1, 3, 3]),
map: new Map([[1, 2]]),
regex: /foo/,
deep: {array: [ new File(someBlobData, 'file.txt') ] },
error: new Error('Hello!')
}
kitchenSink.circular = kitchenSink
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
能力实现深度拷贝对象。每种形式都有其优缺点,具体应用形式取决于你的需要和指标对象的类型。
参考
- Deep Cloning Objects in JavaScript, the Modern Way(www.builder.io/blog/structured-clone)
- mozilla structuredClone(developer.mozilla.org/zh-CN/docs/Web/API/structuredClone)
看完本文如果感觉有用,记得点个赞反对,珍藏起来说不定哪天就用上啦~
专一前端开发,分享前端相干技术干货,公众号:南城大前端(ID: nanchengfe)