【JavaScript】深拷贝和浅拷贝

2023-09-18 12:06:17

在 JavaScript 中,深拷贝(Deep Copy)和浅拷贝(Shallow Copy)是两种不同的对象复制方法,它们涉及到如何复制对象的属性以及如何处理对象内部的嵌套引用。以下是它们的解释:

浅拷贝(Shallow Copy):

浅拷贝是一种对象复制方法,它仅复制对象的一层属性,而不会递归复制对象内部的嵌套对象。当你进行浅拷贝时,复制的新对象和原始对象会共享相同的嵌套对象引用。

在 JavaScript 中,常见的浅拷贝方法包括:

  1. Object.assign()

    const shallowCopy = Object.assign({}, originalObject);
    
  2. 扩展操作符 (…) 或 Object Spread

    const shallowCopy = { ...originalObject };
    
  3. Array.slice()(适用于数组):

    const shallowCopy = originalArray.slice();
    
  4. Array.concat()(适用于数组):

    const shallowCopy = [].concat(originalArray);
    

浅拷贝的特点是,原始对象和浅拷贝后的对象之间共享相同的引用,因此对于嵌套对象来说,它们会在两者之间保持一致,如果修改了嵌套对象,两者都会受到影响。

深拷贝(Deep Copy):

深拷贝是一种对象复制方法,它会递归地复制对象及其所有嵌套对象,确保复制后的对象与原始对象完全独立,不共享任何引用关系。深拷贝会创建一个全新的对象,包括对象内部的所有属性和嵌套对象。

在 JavaScript 中,实现深拷贝通常需要使用递归方法或者使用专门的深拷贝库,因为原生 JavaScript 并没有提供内置的深拷贝方法。以下是一个使用递归实现深拷贝的简单示例:

function deepCopy(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj; // 如果是基本类型或 null,直接返回
  }

  if (Array.isArray(obj)) {
    // 处理数组
    const newArray = [];
    for (let i = 0; i < obj.length; i++) {
      newArray[i] = deepCopy(obj[i]);
    }
    return newArray;
  }

  // 处理普通对象
  const newObj = {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepCopy(obj[key]);
    }
  }
  return newObj;
}

请注意,深拷贝的实现可能会更复杂,因为需要处理各种情况,例如循环引用和特殊对象类型。因此,通常建议使用成熟的深拷贝库(如 lodash 的 _.cloneDeep 或 jQuery 的 $.extend(true, {}, obj))来确保正确处理各种情况。深拷贝也可能会更消耗内存和性能,因此在使用时要慎重考虑。

解决方法

解决 JavaScript 中的深拷贝问题可以使用不同的方法,以下是几种常见的解决方法:

  1. 使用递归实现深拷贝

    可以编写一个递归函数,该函数遍历对象的属性并进行深度复制。当遇到嵌套对象时,递归调用该函数。这是一个简单的示例:

    function deepCopy(obj) {
        if (obj === null || typeof obj !== 'object') {
            return obj; // 如果是基本类型或 null,直接返回
        }
    
        if (Array.isArray(obj)) {
            // 处理数组
            return obj.map(item => deepCopy(item));
        }
    
        // 处理普通对象
        const newObj = {};
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                newObj[key] = deepCopy(obj[key]);
            }
        }
        return newObj;
    }
    
    const originalObject = { a: 1, b: { c: 2 } };
    const deepClone = deepCopy(originalObject);
    

    这个方法的好处是你可以完全控制深拷贝的实现,但要注意处理循环引用和特殊对象类型。

  2. 使用第三方库

    有很多第三方库可以执行深拷贝,其中一些库非常成熟且能够处理复杂情况。例如,Lodash 提供了 _.cloneDeep 方法,可以深度复制对象:

    const _ = require('lodash');
    
    const originalObject = { a: 1, b: { c: 2 } };
    const deepClone = _.cloneDeep(originalObject);
    

    这种方法通常是最安全和最方便的,因为这些库已经考虑了大多数深拷贝的边界情况。

  3. 使用 JSON 序列化和反序列化

    这种方法对于没有包含函数、循环引用等特殊情况的对象非常有效。你可以将对象转换为 JSON 字符串,然后再将其解析回对象,这将创建一个新的对象副本。

    const originalObject = { a: 1, b: { c: 2 } };
    const deepClone = JSON.parse(JSON.stringify(originalObject));
    

    请注意,这种方法有一些限制,例如它无法处理函数、特殊的 JavaScript 对象类型(如正则表达式、Date 对象)以及循环引用。

选择哪种深拷贝方法取决于你的需求和对象的复杂性。如果对象非常简单且不包含特殊类型,JSON 序列化方法可能足够了。否则,使用成熟的第三方库或编写自己的深拷贝函数可能是更好的选择。

更多推荐

SpringBoot+Jpa+Thymeleaf实现增删改查

SpringBoot+Jpa+Thymeleaf实现增删改查这篇文章介绍如何使用Jpa和Thymeleaf做一个增删改查的示例。1、pom依赖pom包里面添加Jpa和Thymeleaf的相关包引用<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://mave

Linux 信号集 及其 部分函数

这几个函数都是对自己自定义的信号集操作intsigemptyset(sigset_t*set)功能:清空信号集中的数据,将所有的标志位置为0参数:set需要操作的信号集返回值:成功0失败-1intsigfillset(sigset_t*set)功能:清空信号集中的数据,将所有的标志位置为1参数:set需要操作的信号集返

数据结构---二叉搜索树

二叉搜索树二叉搜索树什么是二叉搜索树?二叉搜索树的操作查找插入删除源代码非递归版二叉搜索树什么是二叉搜索树?二叉搜索树(BinarySearchTree简称BST)又称二叉排序树,是一种二叉树的特殊形式,它在每个节点上存储的键值满足以下性质:若它的左子树不为空,则左子树上的所有节点的值都小于根节点的值若它的右子树不为空

数据结构--7.1散列表(哈希表)查找

散列表查找我们要在a[]中查找key关键字的记录:——顺序表查找:挨个儿查找——有序表查找:二分法查找——散列表查找记录的存储位置=f(关键字)散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。这里我们把这种对应关系f称为散列函数,又成为哈希(Hash

EM算法和VAE的学习笔记

文章目录摘要EM算法流程EM算法对GMM的参数估计EM算法的证明EM算法的另一种理解VAE参考文献摘要这是我学习EM算法(Expectation-MaximizationAlgorithm)和VAE(VariationalAuto-Encoder)的学习笔记,首先总结了EM算法流程,然后举了一个例子,用EM算法对GMM

【karle 笔记】QQ机器人jdk17版本下载和安装

这里写自定义目录标题下载地址安装JDK:安装JRE验证安装成功下载地址https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe下载后,是一个exe文件,傻瓜式安装即可安装JDK:直接用安装包安装,默认安装路径在:C:\ProgramFil

ChatGPT技术原理

目录一、Tokenization二、Transformer模型三、预训练四、微调五、Beamsearch总结自从OpenAI的ChatGPT在2022年底横空出世以来,这款大型语言模型在各种任务中都展现了惊人的性能,包括问答、对话、文本生成等。ChatGPT以其卓越的性能和高效的处理能力,引领了自然语言处理(NLP)领

vue/react/node项目通过eslint检查语法规范

首先我们打开终端全局安装依赖npminstall-geslint然后以管理员身份运行项目终端输入eslint--init然后这里在初始化时会问我们想如何使用它?分别对应仅检查语法检查语法并发现问题检查语法、发现问题并强制执行代码样式这里建议第二种第三种肯定是不行的然后问我们您的项目使用哪种类型的模块?JavaScrip

日主题RiPro主题高端美化/设计素材软件下载站专用子主题/美化包源码(升级版/免拓展)

主题简介日主题RiPro主题高端美化/设计素材软件下载站专用子主题/美化包源码,这个子主题美化包无授权无暗链,不用再修改原主题代码,在用这个本美化包前要先下载最新ripro主题,本子主题有版本要求,仅支持RiPro8.0以上版本,建议使用官方正版主题。更新记录:美化网站整站主色调颜色,优化代码结构,更适合SEO新增菜单

文件包含漏洞

1.文件包含原理程序在开发的时候,未对包含的文件进行严格的过滤,攻击者可以构造自己的图片木马当作php执行2.文件包含分类本地包含不需要条件,只要有程序代码漏洞,默认条件就可以包含漏洞远程包含需要allow_url_include=on(开启远程包含功能)、magic_quotes_gpc=off(魔术符号关闭)htt

Flutter与Native通信原理剖析与实践

通信原理我们分几种场景来介绍Flutter和Native之间的通信。Native发送数据给FlutterFlutter发送数据给NativeFlutter发送数据给Native,然后Native回传数据给FlutterFlutter与Native通信机制在讲解Flutter与Native之间是如何传递数据之前,我们先了

热文推荐