当前位置: 首页 > Web前端 > HTML

使用结构化克隆在JavaScript中深度复制

时间:2023-03-28 15:40:55 HTML

很长一段时间,您不得不求助于变通方法和库来创建JavaScript值的深度副本。现在js提供了structuredClone()一个内置函数用于深拷贝。浏览器支持:浅拷贝在JavaScript中拷贝一个值几乎是浅拷贝,而不是深拷贝。这意味着对深层嵌套值的更改将在副本中以及原始值中可见。在JavaScript中创建浅拷贝的一种方法是使用对象展开运算符constmyOriginal={someProp:"withastringvalue",anotherProp:{withAnotherProp:1,andAnotherProp:true}};constmyShallowCopy={...myOriginal};直接在浅拷贝上添加或更改属性只会影响拷贝,不会影响原始值:myShallowCopy.aNewProp="anewvalue";console.log(myOriginal.aNewProp)//^记录`undefined`但是,添加或更改深度嵌套的属性会同时影响原始值和复制的值:myShallowCopy.anotherProp.aNewProp="anewvalue";console.log(myOriginal.anotherProp.aNewProp)//^logs`anewvalue`objectspreadoperator遍历myOriginal的所有可枚举属性。它获取属性名称和值,并将它们一一分配给一个新创建的空对象。因此,生成的对象在形状上是相同的,但具有自己的属性和值列表副本。这些值也被复制,但JavaScript值处理所谓的原始类型与非原始类型的方式不同。非基本类型被视为引用,这意味着复制值的行为实际上只是复制对同一底层对象的引用,从而导致浅拷贝行为。深拷贝与浅拷贝相反的是深拷贝。深拷贝算法也是一个一个地拷贝一个对象的属性,但是当它找到另一个对象的引用时递归地调用自己,同时创建那个对象的副本。这对于确保两段代码不会意外共享一个对象并在不知不觉中操纵彼此的状态很重要。过去,在JavaScript中创建值的深层副本并不简单或好方法。许多人依赖第三方库,例如Lodash的cloneDeep()函数。可以说,这个问题最常见的解决方案是基于JSON的hack:constmyDeepCopy=JSON.parse(JSON.stringify(myOriginal));事实上,这是一个非常流行的解决方法,以至于V8积极优化JSON.parse(),尤其是上面的模式,以使其尽可能快。虽然速度很快,但它也有一些缺点:递归数据结构:JSON.stringify()在序列化递归数据结构时会报错。这在使用链表或树时很容易发生。内置类型:JSON.stringify()如果值包含其他JS关键字,如Map、Set、Date、RegExp或ArrayBuffer,也会报错。函数:JSON.stringify()可能会删除函数。结构化克隆浏览器已经要求能够在几个地方创建JavaScript值的深拷贝:在IndexedDB中存储JS值需要某种形式的序列化,以便它们可以存储在磁盘上,然后反序列化以恢复JS值。同样,向WebWorker发送消息postMessage()需要将JS值从一个JS领域传输到另一个。修改了HTML规范以公开一个名为structuredClone()的函数,该函数可以完整运行该算法,作为开发人员轻松创建JavaScript值的深层副本的一种方式。constmyDeepCopy=structuredClone(myOriginal);特性和限制结构化克隆解决了JSON.stringify()技术的许多(虽然不是全部)缺点。结构化克隆可以处理循环数据结构,支持许多内置数据类型,并且通常更健壮且通常更快。然而,它仍然有一些可能让您措手不及的限制:原型:如果structuredClone()与类实例一起使用,您将获得一个普通对象作为返回值,因为结构化克隆会丢弃对象的原型链。功能:也不支持功能。Non-cloneables:一些值在结构上不可克隆,最显着的是错误和DOM节点。它会导致structuredClone()抛出异常。如果这些限制中的任何一个破坏了您的用例,像Lodash这样的库仍然提供其他深度克隆算法的自定义实现,这些算法可能适合也可能不适合您的用例。