在很长一段时间内,您不得不求助于变通方法和库来创建 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 中进行深度复制的更多相关文章

  1. 深度解析javascript中的浅复制和深复制

    原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...

  2. javascript 数组的深度复制

    javascript 数组的深度复制 一般情况下,使用 "=" 可以实现赋值.但对于数组.对象.函数等这些引用类型的数据,这个符号就不好使了. 1. 数组的简单复制 1.1 简单遍 ...

  3. javascript中关于深复制与浅复制的问题

    在javascript中,变量的类型分为基本类型和引用类型. 对于基本类型的变量来说,值的复制以及作为函数参数实参传递的过程都是值的复制传递,换句话说,是会在内存中开辟出一个新空间用于存放新的值的.这 ...

  4. 【转】JavaScript中的对象复制(Object Clone)

    JavaScript中并没有直接提供对象复制(Object Clone)的方法.因此下面的代码中改变对象b的时候,也就改变了对象a. a = {k1:1, k2:2, k3:3}; b = a; b. ...

  5. javascript 中的深复制 和 其实现方法

    首先,我们需要明白什么是深复制(侧重指对象方面)? 在javascript中,复制分为浅复制和深复制,个人理解,浅复制就是直接将引用复制,复制前后的两个对象指向同一个内存地址,对其中一个进行操作,另外 ...

  6. 深入探讨JavaScript如何实现深度复制(deep clone)

    在代码复用模式里面有一种叫做“复制属性模式”(copying properties pattern).谈到代码复用的时候,很有可能想到的是代码的继承性(inheritance),但重要的是要记住其最终 ...

  7. javascript中的浅复制和深复制

    //浅复制:实现基本类型的复制没有问题,但是复制的是引用类型的话,则修改child将会修改parent function extend(parent,child){ var child = child ...

  8. C# 中如何深度复制某一个类型(备注:可能有 N 个类型需要复制)的对象?

    如题,针对某一个特定的类型,深度复制,没有那么难,最起码可以手动赋值,但如果要针对 N 多类型深度复制,最简单的方法,是把这个对象序列化成 XML.JSON 或其它可以序列化的载体,然后再将这个载体反 ...

  9. (译文)JavaScript基础——JavaScript中的深拷贝

    在JavaScript中如何拷贝一个对象? 通过引用调用 function mutate(obj) { obj.a = true; } const obj = {a: false}; mutate(o ...

随机推荐

  1. 转:Java多线程基础问题

    如果你即将去一家从事大型系统研发的公司进行Java面试,不可避免的会有多线程相关的问题.下面是一些针对初学者或者新手的问题,如果你已经具备良好的基础,那么你可以跳过本文,直接尝试针对进阶水平的Java ...

  2. Arcpy按属性(字段值)不同将shp分割为多个独立shp_适用点线面矢量

    利用代码可以进行批量处理,安装有10.5及以上版本ArcGIS可以使用工具Split by attributes完成上述任务 # -*- coding: utf-8 -*- # Import syst ...

  3. java 8 启动脚本优化 2

    #!/bin/bash #链接文件 source /etc/profile #java虚拟机启动参数 #通过http://xxfox.perfma.com/jvm/check来检查参数的合理性 JAV ...

  4. Stun协议实现

    在现实Internet网络环境中,大多数计算机主机都位于防火墙或NAT之后,只有少部分主机能够直接接入Internet.很多时候,我们希望网络中的两台主机能够直接进行通信(即所谓的P2P通信),而不需 ...

  5. Various methods for capturing the screen

    Explains techniques for capturing the screen programmatically. Download GDI source code - 72.1 Kb Do ...

  6. MindSpore联邦学习框架解决行业级难题

    内容来源:华为开发者大会2021 HMS Core 6 AI技术论坛,主题演讲<MindSpore联邦学习框架解决隐私合规下的数据孤岛问题>. 演讲嘉宾:华为MindSpore联邦学习工程 ...

  7. echarts map 地图在react项目中的使用

    需求 展示海南省地图,点击市高亮展示,并在右侧展示对应市的相关数据. 准备工作 Echarts 海南地图json 效果图 代码 index.tsx import React, { useRef, us ...

  8. 总结Vue第一天:简单介绍、基本常用知识、辅助函数

    总结Vue第一天:简单介绍.基本常用知识.辅助函数 中文官网:https://cn.vuejs.org/v2/guide/syntax.html 遇到不熟悉的可以先看一下官网,然后再看一下一些别人写的 ...

  9. JAVA判断是否是微信内置浏览器,是否是在微信内打开

    /** * 通过请求头判断是否是微信内置浏览器,是否是在微信内打开 * @param request * @return */ @RequestMapping(value = "/hello ...

  10. Linux C(++)获取可执行程序完整路径

    代码 #include <sys/statfs.h> #include <string> #include <iostream> #include <limi ...