使用结构化克隆在 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 ...
随机推荐
- CF132A Turing Tape 题解
Content 读入一个字符串 \(s\),让你用以下规则将字符串中的所有字符转换成数字: 先将这个字符的 \(\texttt{ASCII}\) 码的 \(8\) 位 \(2\) 进制数反转,再将这个 ...
- Qt-Vnc远程
VNC简介 VNC(Virtual Network Computing)是基于RFB(Remote Frame Buffer)协议的远程系统,C/S端口默认为5900,B/S端口默认为5800. RF ...
- vnc mirror driver
2012年4月,大二下学期,平静的课堂上老师通知了一个比赛...第一届大学生软件设计大赛!然后我选了第六题:windows屏幕录像.就这样我就开始了我的vc开发生涯. 之前学了c/c++作为基础,自认 ...
- React使用css module和className多类名设置
引入样式文件 import styles from './footer.module.css'; 注意: 样式文件名必须要以.module.css结尾 单类名设置 <div className= ...
- AcWing1264. 动态求连续区间和 (线段树做法)
1.题目 给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,b] 的连续和. 输入格式 第一行包含两个整数 n 和 m,分别表示数的个数和操作次数. 第二行包含 n ...
- 【LeetCode】922. Sort Array By Parity II 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 使用奇偶数组 排序 奇偶数位置变量 日期 题目地址: ...
- Balancing Act(poj1655)
Balancing Act Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12703 Accepted: 5403 De ...
- Codeforces 777C:Alyona and Spreadsheet(预处理)
During the lesson small girl Alyona works with one famous spreadsheet computer program and learns ho ...
- BeanUtils属性转换工具
commons 包的 BeanUtils 进行属性拷贝性能较差:Spring 的 BeanUtils 性能相对较好. public class A { private String name; pri ...
- Generative Modeling by Estimating Gradients of the Data Distribution
目录 概 主要内容 Langevin dynamics Score Matching Denoising Score Matching Noise Conditional Score Networks ...