首页IT科技深拷贝浅拷贝的区别(记录–一种更现代的深浅拷贝方法)

深拷贝浅拷贝的区别(记录–一种更现代的深浅拷贝方法)

时间2025-07-30 14:34:39分类IT科技浏览6832
导读:这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助...

这里给大家分享我在网上总结出来的一些知识                ,希望对大家有所帮助

你是否知道                         ,JavaScript中有一种原生的方法来做对象的深拷贝?

本文我们要介绍的是structuredClone函数        ,它是内置在 JavaScript 运行时中的:

在上面的示例中        ,我们不仅拷贝了对象                         ,还拷贝了嵌套数组                 ,甚至拷贝了Date对象:

copied.attendees // ["Steve"] copied.date // Date: Wed Dec 31 1969 16:00:00 cocalendarEvent.attendees === copied.attendees // false

没错        ,structuredClone 不仅可以做到以上这些                        ,而且还可以:

克隆无限嵌套的对象和数组 克隆循环引用 克隆各种各样的 JavaScript 类型                 ,如 Date, Set, Map, Error, RegExp, ArrayBuffer, Blob, File, ImageData 等等 转移任何可转移的对象

举个例子:

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)

为什么不使用对象扩展运算符进行克隆呢

值得注意的是,我们讨论的是深拷贝                。如果你只需要做一个浅拷贝                        ,也就是一个不复制嵌套对象或数组的拷贝                         ,那么我们可以只做一个对象扩展:

const simpleEvent = { title: "前端修罗场", } const shallowCopy = {...calendarEvent}

或者你也可以使用这种方法:

const shallowCopy = Object.assign({}, simpleEvent) const shallowCopy = Object.create(simpleEvent)

但是一旦我们有了嵌套项,我们就会遇到麻烦:

const calendarEvent = { title: "前端修罗场", date: new Date(123), attendees: ["Steve"] } const shallowCopy = {...calendarEvent} shallowCopy.attendees.push("Bob") shallowCopy.date.setTime(456)

如上所见                ,我们没有对该对象进行完整复制                         。

嵌套日期和数组仍然是两者之间的共享引用                         ,如果我们想编辑它们        ,认为我们只是更新复制的日历事件对象                ,这可能会导致重大问题        。

为什么不使用JSON.parse(JSON.stringify(x)) ?

它实际上是一个很棒的工具                         ,性能令人惊讶        ,但也有一些structuredClone可以解决的缺点        。

举个例子:

const calendarEvent = { title: "前端修罗场", date: new Date(123), attendees: ["Steve"] } const problematicCopy = JSON.parse(JSON.stringify(calendarEvent))

如果我们输出 problematicopy        ,我们会得到:

{ title: "前端修罗场", date: "1970-01-01T00:00:00.123Z" attendees: ["Steve"] }

这不是我们想要的 date 格式                         ,因为格式应该是date对象                 ,而不是字符串                         。

这是因为 JSON.Stringify 只能处理基本对象                 、数组和基本类型                 。任何其他类型都可能以难以预测的方式处理        。例如        ,日期被转换为字符串                        。但是 Set 对象就会被简单地转换为 {}                 。

同时                        ,JSON.Stringify 甚至会完全忽略某些东西                 ,如 undefined 或 function。

例如,如果我们用这个方法复制下面这个例子:

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": {}, }

可以看到                         , 这种方法的拷贝出错了                        。

因此,如果我们的需求适合这个方法                ,可以用这个方法                         。但是                         ,我们可以用 structuredClone 做这个方法有很多不能做的事情。

为什么不是 _.cloneDeep?

到目前为止        ,Lodash 的 cloneDeep 函数是这个问题的一个非常常见的解决方案                。事实上                ,这确实也像预期的那样工作:

import cloneDeep from lodash/cloneDeep const calendarEvent = { title: "前端修罗场", date: new Date(123), attendees: ["Steve"] } // ✅ const clonedEvent = structuredClone(calendarEvent)

但是                         ,这里有一个警告                         。根据我的 IDE 中的导入成本扩展        ,打印任何我导入函数的成本        ,这个函数占了 17.4kb` 的大小(5.3kb gzip):

假设你只导入了这个函数        。如果改用更常见的方式导入                         ,没有意识到摇树并不总是按希望的方式工作                 ,那么可能会无意中为这个函数导入高达2 5kb 的文件?

什么是 structuredClone 克隆不了的

函数不能被克隆

structuredClone({ fn: () => { } }) // 会抛出一个 DataCloneError 异常

DOM 节点不能克隆

structuredClone({ el: document.body })// 会抛出一个 DataCloneError 异常

属性描述符 setter和getter 不能克隆

类似元数据的特性也不会被克隆                。

例如        ,使用 getter                        ,结果值会被克隆                 ,但不会克隆 getter 函数本身(或任何其他属性元数据):

structuredClone({ get foo() { return bar } }) // log: { foo: bar }

对象属性不能被克隆

原型链不会被遍历或复制                         。因此,如果克隆MyClass的一个实例                        ,克隆的对象将不再是该类的实例(但该类的所有有效属性将被克隆)

class MyClass { foo = bar myMethod() { /* ... */ } } const myClass = new MyClass() const cloned = structuredClone(myClass) // log: { foo: bar } cloned instanceof myClass // false

structuredClone 支持类型的完整列表

更简单地说                         ,任何不在下面列表中的东西都不能克隆:

JS 内置类型:Array, ArrayBuffer, Boolean, DataView, Date, Error types (those specifically listed below), Map , Object but only plain objects (e.g. from object literals), Primitive types, except symbol (aka number, string, null, undefined, boolean, BigInt), RegExp, Set, TypedArray

Error types: Error, EvalError, RangeError, ReferenceError , SyntaxError, TypeError, URIError

Web/API types: AudioData, Blob, CryptoKey, DOMException, DOMMatrix, DOMMatrixReadOnly, DOMPoint, DomQuad, DomRect, File, FileList, FileSystemDirectoryHandle, FileSystemFileHandle, FileSystemHandle, ImageBitmap, ImageData, RTCCertificate, VideoFrame

浏览器支持

所有主流浏览器都支持 structuredClone,甚至Node.js和Deno        。

不过在 Web worker 中                ,目前支持是比较有限的        。

本文转载于:

https://juejin.cn/post/7209226686372692029

如果对您有所帮助                         ,欢迎您点个关注        ,我会定时更新技术文档                ,大家一起讨论学习                         ,一起进步                         。

声明:本站所有文章        ,如无特殊说明或标注        ,均为本站原创发布                 。任何个人或组织                         ,在未征得本站同意时                 ,禁止复制                        、盗用        、采集                 、发布本站内容到任何网站                         、书籍等各类媒体平台        。如若本站内容侵犯了原著者的合法权益        ,可联系我们进行处理                        。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
长葛官方网站(长葛的厂) 提高曝光率和点击率的营销方法(如何高效利用SEO推广提升网站曝光度)