关于javascript:使用结构化克隆在-JavaScript-中进行深度复制

39次阅读

共计 1853 个字符,预计需要花费 5 分钟才能阅读完成。

在很长一段时间内,您不得不求助于变通方法和库来创立 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 这样的库依然提供其余深度克隆算法的自定义实现,这些算法可能适宜您的用例,也可能不适宜您的用例。

正文完
 0