使用结构化克隆在 JavaScript 中进行深度复制
在很长一段时间内,您不得不求助于变通方法和库来创建 JavaScript 值的深层副本。现在js提供 「structuredClone()」 一个用于深度复制的内置函数。
浏览器支持:
浅拷贝
在 JavaScript 中复制一个值几乎是浅拷贝,而不是深拷贝。这意味着对深度嵌套值的更改将在副本和原始值中可见。
使用对象扩展运算符 在 JavaScript 中创建浅拷贝的一种方法
const myOriginal = {
someProp: "with a string value",
anotherProp: {
withAnotherProp: 1,
andAnotherProp: true
}
};
const myShallowCopy = {...myOriginal};
直接在浅副本上添加或更改属性只会影响副本,而不影响原始值:
myShallowCopy.aNewProp = "a new value";
console.log(myOriginal.aNewProp)
// ^ logs `undefined`
然而,添加或更改嵌套很深的属性会影响原始值和拷贝值:
myShallowCopy.anotherProp.aNewProp = "a new value";
console.log(myOriginal.anotherProp.aNewProp)
// ^ logs `a new value`
对象扩展运算符遍历了myOriginal所有可枚举的属性。它使用属性名称和值,并将它们一一分配给一个新创建的空对象。因此,生成的对象在形状上是相同的,但具有自己的属性和值列表的副本。这些值也会被复制,但是 JavaScript 值处理所谓的基本类型的方式与处理非基本类型的方式不同。
非基本类型作为引用处理,这意味着复制值的行为实际上只是复制对同一底层对象的引用,从而导致浅复制行为。
深拷贝
与浅拷贝相反的是深拷贝。深拷贝算法也一个一个地拷贝一个对象的属性,但是当它找到对另一个对象的引用时递归地调用自己,同时创建该对象的副本。这对于确保两段代码不会意外共享一个对象并在不知不觉中操纵彼此的状态非常重要。
在 JavaScript 中创建值的深层副本过去没有简单或好的方法。很多人依赖第三方库,比如Lodash 的cloneDeep()函数。可以说,这个问题最常见的解决方案是基于 JSON 的 hack:
const myDeepCopy = JSON.parse(JSON.stringify(myOriginal));
事实上,这是一个非常流行的解决方法,V8 积极优化 JSON.parse(),特别是上面的模式,以使其尽可能快。虽然速度很快,但它也有一些缺点:
递归数据结构:JSON.stringify()当你序列化一个递归数据结构时会报错。在使用链表或树时,这很容易发生。 内置类型:JSON.stringify()如果值包含其他JS关键字,例如Map,Set,Date,RegExp或ArrayBuffer,也会报错。 Functions:JSON.stringify()有可能会丢掉函数。
结构化克隆
浏览器已经需要在几个地方创建 JavaScript 值的深层副本的能力:在 IndexedDB 中存储 JS 值需要某种形式的序列化,以便可以将其存储在磁盘上,然后反序列化以恢复 JS 值。类似地,向 WebWorker 发送消息postMessage()需要将 JS 值从一个 JS 领域传输到另一个领域。
HTML 规范进行了修改,以公开一个名为的函数structuredClone(),该函数完全运行该算法,作为开发人员轻松创建 JavaScript 值的深层副本的一种手段。
const myDeepCopy = structuredClone(myOriginal);
特点和限制
结构化克隆解决了该JSON.stringify()技术的许多(尽管不是全部)缺点。结构化克隆可以处理循环数据结构,支持许多内置数据类型,并且通常更健壮且通常更快。
但是,它仍然有一些限制可能会让您措手不及:
Prototypes:如果structuredClone()与类实例一起使用,您将获得一个普通对象作为返回值,因为结构化克隆会丢弃对象的原型链。 函数:同样不支持函数。 Non-cloneables:一些值不是结构化可克隆的,最值得注意的是Error和 DOM 节点。它会导致structuredClone()抛出异常。
如果这些限制中的任何一个对您的用例造成破坏,像 Lodash 这样的库仍然提供其他深度克隆算法的自定义实现,这些算法可能适合您的用例,也可能不适合您的用例。
使用结构化克隆在 JavaScript 中进行深度复制的更多相关文章
- 深度解析javascript中的浅复制和深复制
原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...
- javascript 数组的深度复制
javascript 数组的深度复制 一般情况下,使用 "=" 可以实现赋值.但对于数组.对象.函数等这些引用类型的数据,这个符号就不好使了. 1. 数组的简单复制 1.1 简单遍 ...
- javascript中关于深复制与浅复制的问题
在javascript中,变量的类型分为基本类型和引用类型. 对于基本类型的变量来说,值的复制以及作为函数参数实参传递的过程都是值的复制传递,换句话说,是会在内存中开辟出一个新空间用于存放新的值的.这 ...
- 【转】JavaScript中的对象复制(Object Clone)
JavaScript中并没有直接提供对象复制(Object Clone)的方法.因此下面的代码中改变对象b的时候,也就改变了对象a. a = {k1:1, k2:2, k3:3}; b = a; b. ...
- javascript 中的深复制 和 其实现方法
首先,我们需要明白什么是深复制(侧重指对象方面)? 在javascript中,复制分为浅复制和深复制,个人理解,浅复制就是直接将引用复制,复制前后的两个对象指向同一个内存地址,对其中一个进行操作,另外 ...
- 深入探讨JavaScript如何实现深度复制(deep clone)
在代码复用模式里面有一种叫做“复制属性模式”(copying properties pattern).谈到代码复用的时候,很有可能想到的是代码的继承性(inheritance),但重要的是要记住其最终 ...
- javascript中的浅复制和深复制
//浅复制:实现基本类型的复制没有问题,但是复制的是引用类型的话,则修改child将会修改parent function extend(parent,child){ var child = child ...
- C# 中如何深度复制某一个类型(备注:可能有 N 个类型需要复制)的对象?
如题,针对某一个特定的类型,深度复制,没有那么难,最起码可以手动赋值,但如果要针对 N 多类型深度复制,最简单的方法,是把这个对象序列化成 XML.JSON 或其它可以序列化的载体,然后再将这个载体反 ...
- (译文)JavaScript基础——JavaScript中的深拷贝
在JavaScript中如何拷贝一个对象? 通过引用调用 function mutate(obj) { obj.a = true; } const obj = {a: false}; mutate(o ...
随机推荐
- IOS 真机调试和发布相关证书
一.成员介绍1. Certification(证书)证书是对电脑开发资格的认证,每个开发者帐号有一套,分为两种:1) Developer Certification(开发证书)安装在电脑上 ...
- 记录一次成功CICD完整亲身实践从此踏进入Devops大门
Devops概念 DevOps 强调通过一系列手段来实现既快又稳的工作流程,使每个想法(比如一个新的软件功能,一个功能增强请求或者一个 bug 修复)在从开发到生产环境部署的整个流程中,都能不断地为用 ...
- 工厂为什么要进行计划排产,APS高级计划排程系统的优势作用是什么?
我们每个人的指挥中心是大脑,大脑对我们身体发出各种各样的指令,不停的告诉我们身体去干什么. 那么,一个制造企业的指挥中心是哪里?工厂每天都会接到各种各样的订单,通过几百上千的工人,使用各种设备来生产. ...
- vscode提示提示安装似乎损坏,请重新安装
安装 Fix VSCode Checksums 插件 Ctrl+Shift+P , 输入Fix Checksums : Apply, 点击,重启即可
- 微软要放弃Electron了???聊聊WebView2
有好几个公众号发文说"微软要放弃Electron了",实际情况是微软旗下的Teams产品打算把Electron框架换成WebView2而已.接下来我就聊一下这个事情: 微软不会放弃 ...
- Spring Boot整合Thymeleaf及Thymeleaf页面基本语法
引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp ...
- Windows串口之解决包含setupapi.h还提示找不到符号报错
关于 本文演示环境: win10 1909 + VS2017 1. 错误信息 明明已经添加了头文件setupapi.h 和 库 setupapi.lib, 却还是提示报错,报错信息: 1>C:\ ...
- 【LeetCode】438. Find All Anagrams in a String 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 滑动窗口 双指针 日期 题目地址:https://l ...
- 【LeetCode】486. Predict the Winner 解题报告(Python)
[LeetCode]486. Predict the Winner 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: ht ...
- 【LeetCode】842. Split Array into Fibonacci Sequence 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...