首页 > 其他分享 >记录--一种更现代的深浅拷贝方法

记录--一种更现代的深浅拷贝方法

时间:2023-03-16 18:22:05浏览次数:35  
标签:const 克隆 structuredClone -- 深浅 date new 拷贝 calendarEvent

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

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

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

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

const copied = structuredClone(calendarEvent)

在上面的示例中,我们不仅拷贝了对象,还拷贝了嵌套数组,甚至拷贝了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):

image.png

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

标签:const,克隆,structuredClone,--,深浅,date,new,拷贝,calendarEvent
From: https://www.cnblogs.com/smileZAZ/p/17223748.html

相关文章

  • CAP
    分布式系统技术就是用来解决集中式架构的性能瓶颈问题,来适应快速发展的业务规模分布式系统是建立在网络之上的硬件或者软件系统,彼此之间通过消息等方式进行通信和协调。......
  • js倒计时-4章引例
    如题:故意用了中文变量名,现实中大家酌情取舍。1.js1functionf1(){2let今天=newDate();3let未来=newDate("2023-6-1");4let差距=未来-今天......
  • javascript addEventListener
    addEventListenerEventTarget.addEventListener()方法将指定的监听器注册到EventTarget上,当该对象触发指定的事件时,指定的回调函数就会被执行。1.1EventTarget可以......
  • Linux 安装.NET 6.0 SDK
    1下载SDKhttps://dotnet.microsoft.com/zh-cn/download/dotnet/6.0  2创建dotnet文件夹并解压SDKmkdir-p$HOME/dotnet&&tarzxfdotnet-sdk-6.0.407-linux-......
  • 438.Find All Anagrams in a String
    给定两个字符串 s 和p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。异位词指由相同字母重排列形成的字符串(包括相同的字符......
  • python并行计算demo,用于求0~n之间的素数之和
     想试试服务器的并行计算能力,就让cpu慢慢计算,计算0~n之间所有素数之和设置target为结尾,num_of_processors为进程数,即可开始跑如下所示frommultiprocessingimportP......
  • JavaScript基础
    JS是什么是运行在浏览器的编程语言,由ECMAscript(基础语法)+DOM+BOM组成。导入方式导入方式有三种,内部导入、外部导入、行内导入注意:script便签加在/body前为妙......
  • (五)博客园美化(风格1):音乐插件等小模块的运用
    空闲的时候自己根据很多大神的美化教程,把自己的博客园简单装修了下。再此整理一下美化方式和步骤,如果喜欢本人博客这种风格,可以参考一下这个系列。一、ForkmeonGitee......
  • 【插件介绍】Mesh2Geom插件
    MeshtoGeometryPlugin,来自达索官方论坛社区原帖链接:MeshtoGeometryPluginpluginfeature:允许Abaqus用户从网格文件生成几何图形。该插件可以将.STL文件和网......
  • 3.1.1 线程池
    LinuxC/C++服务器线程池某类任务非常耗时(磁盘io或网络io),严重影响该线程处理其他任务,解决办法就是把这些耗时任务放到其他线程异步去执行线程资源的开效与cpu核心之间......