JavaScript高级:深浅拷贝

news2024/11/26 18:48:07

目录

1 引言

2 浅拷贝

2.1 拷贝数组

 1.2 拷贝对象

3 赋值操作和浅拷贝的比较

4 深拷贝

4.1 前置知识 --> 递归函数

4.2 使用递归实现深拷贝

4.3 js库中的lodash里面的cloneDeep内部实现深拷贝

4.4 利用JSON实现深拷贝


深浅拷贝只针对引用数据类型

1 引言

假如我们想要使用一个对象,我们之前通常使用赋值的方式,但是使用赋值的方式时,修改赋值后的对象中的数据,会影响原对象!!!

比如:

const obj = {
      name: '张三',
      age: 18,
}
console.log(obj)
const obj2 = obj;
obj2.name = '李四'
console.log(obj2)
console.log(obj)


而上述的代码只是修改了简单数据类型,如果修改复杂数据类型结果更是如此了!!!

2 浅拷贝

浅拷贝遇到复杂的数据类型拷贝的是地址

2.1 拷贝数组

方式一:

const arr1 = [1, 2, 3]
const arr = [...arr1]
console.log(arr)
arr[0] = 100
console.log(arr)
console.log(arr1)


方式二:

const arr1 = [1, 2, 3]
const arr2 = arr1.concat()
console.log(arr2)
arr2[0] = 100
console.log(arr2)
console.log(arr1)

以上两种方式可以实现单层数组的拷贝,那么如果我们遇到嵌套的数组,使用这种方式还可以吗? 

例:

const arr1 = [1, [1, 2, 3], 3]
const arr2 = arr1.concat()
console.log(arr2)
arr2[1][2] = 100
console.log(arr2)
console.log(arr1)

此时我们修改拷贝后得到的数组中的数据发现,原数组也被修改了。所以当遇到单层的数组时,拷贝时,数组中只是简单数据类型,修改不会影响原数组,但是如果是嵌套的数据,数组中包含数组,那么拷贝是是直接将内层数组作为一个元素拷贝,数组属于复杂数据类型,所以最终拷贝的是地址


 1.2 拷贝对象

比如以下代码:

const obj = {
      name: '张三',
      age: 18,
      height: 1.88,
      family: {                        
          father: '李四',
          mother: '王五'
      }
}

方式一:

const o = { ...obj }
console.log(o)
o.name = '李四'
console.log(o)
console.log(obj)


方式二:

const o = Object.assign({}, obj)
console.log(o)
o.age = 20
o.family.father = '赵六'
console.log(o)
console.log(obj)

在上面的这段代码中,我们修改拷贝后的对象中的复杂数据类型,结果如下:


3 赋值操作和浅拷贝的比较

1、直接赋值的方式,只要是对象都会相互影响,因为都是直接拷贝的是栈中的地址。

2、浅拷贝如果是一层对象不会相互影响,如果出现多层对象,还是会相互影响。(因为如果拷贝的对象中是简单数据类型,直接拷贝的是值,如果是复杂数据类型拷贝的还是地址)

--->   浅拷贝在直接赋值的不足之处进行了改进,而浅拷贝同样也是需要改进,接下来将介绍深拷贝,将解决浅拷贝的不足之处

4 深拷贝

4.1 前置知识 --> 递归函数

首先递归函数是什么?简单理解就是自己调用自己。

1 例:实现阶乘

【代码】:

function fn(n) {
    if (n <= 1)
         return 1
    return n * fn(n - 1)
}
const re = fn(5)
console.log(re)

2 案例:利用递归函数实现setTimeout 模拟setInterval效果

【代码】:

function getTime() {
    document.querySelector('div').innerHTML = new Date().toLocaleString()
    setTimeout(getTime, 1000)
}
getTime()

4.2 使用递归实现深拷贝

const obj = {
    name: '张三',
    age: 18,
    hobby: ['学习', '喝酒', '烫头'],
    family: {
         father: '张三丰',
         mother: '张三娘'
    }
}

【需求】:现在需要拷贝上述 obj 对象中的所有数据,并且修改拷贝后的对象,不管修改的是简单数据类型,还是复杂数据类型,都不会影响原对象

const obj1 = {}

// 拷贝函数
function deepClone(obj1, obj) {  // onj1是新对象,  obj是旧的
    for (let key in obj) {
        // 处理数组的问题
        if (obj[key] instanceof Array) {
              obj1[key] = []
              deepClone(obj1[key], obj[key])
        } else if (obj[key] instanceof Object) {  // 处理对象的问题  因为arr 也属于对象, 所以判断对象时,写在后面
              obj1[key] = {}
              deepClone(obj1[key], obj[key])
         } else {  // 处理其他数据类型的问题

              obj1[key] = obj[key]
         }
     }
}

deepClone(obj1, obj)
obj1.age = 30
obj1.hobby[0] = '睡觉'
console.log(obj1)
console.log(obj)


4.3 js库中的lodash里面的cloneDeep内部实现深拷贝

1. 首先引入lodash.js文件

也可以使用 npm 直接安装

$ npm i -g npm
$ npm i --save lodash

2 【代码】:

const obj = {
     name: '张三',
     age: 18,
     height: 1.88,
     family: {  // 遇到这种复杂数据类型,拷贝的还是地址, 修改会相互影响
          father: '李四',
          mother: '王五'
     }
}

const obj1 = _.cloneDeep(obj)
obj1.family.father = '赵六'
console.log(obj1)
console.log(obj)



虽然使用js自带的库实现深拷贝比递归的方式简单多了,但是还用引入文件也挺麻烦的,接下来再介绍一种更简单的方式。

4.4 利用JSON实现深拷贝

【代码】:

const obj = {
      name: '张三',
      age: 18,
      height: 1.88,
      family: { 
           father: '李四',
           mother: '王五'
            }
        }

const obj1 = JSON.parse(JSON.stringify(obj))  // 先拿到的是字符串,属于简单数据类型,直接存值

console.log(obj1)
obj1.family.father = '赵六'
console.log(obj1)
console.log(obj)

注意:JSON.stringify()只能处理对象和数组,不能处理函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1426109.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode 19 , 118

19 .删除链表倒数第n个节点 思路1&#xff1a; 我首先想到的就是使用两个loop来进行解决&#xff1a; 遍历所有节点&#xff0c;得到需要删除节点的位置。再遍历一边所有节点&#xff0c;找到需要删除节点进行删除。 解决方案1&#xff1a; class Solution {public ListNod…

DevOps落地笔记-07|案例分析:如何有效管理第三方组件

上一讲主要介绍了如何通过代码预检查的方式提高入库代码的质量&#xff0c;将代码检查尽可能前置&#xff0c;降低修复问题的成本&#xff0c;从而提高交付软件的质量。除了代码本身的问题&#xff0c;依赖组件也是经常困扰开发者的一个问题。比如&#xff0c;依赖组件的某个版…

项目管理构建不只是Maven,还有更优越的它!

教程全文阅读请转至《项目管理构建不只是Maven,还有更优越的它&#xff01;》 Gradle简介 Gradle是一种现代化的构建工具&#xff0c;用于构建Java、C、Python、Android等项目。它是一种基于Groovy语言的自动化构建工具&#xff0c;可以自动化执行各种构建任务&#xff0c;例…

matlab基本操作

目录 1 清空workspace 2 清空命令行窗口 3 求字符的ASCII码 4 矩阵的表示 5 矩阵的转置 6 按列输出 7 求逆矩阵 8 创建零矩阵 9 生成随机数 10 生成空数组 11 生成单位矩阵 12 生成幻方矩阵 13 结构体 14 重复 15 点乘与叉乘 16 寻找符合条件的元素…

2024年1月份实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先&#xff0c;来看下效果图 在线体验地址&#xff1a;https://geojson.hxkj.vip&#xff0c;并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

spring cache的使用(Redis)

要在Spring Boot应用中使用Redis作为缓存&#xff0c;你需要遵循一些步骤来配置和使用Redis。以下是使用Spring Cache抽象与Redis进行整合的详细说明&#xff1a; 1. 添加依赖 首先&#xff0c;需要在pom.xml中添加Spring Boot的Redis starter依赖以及缓存的starter依赖。这会…

vivado 与系统设计师接口

与系统设计师接口 作为迭代I/O和时钟规划过程的一部分&#xff0c;您可以交换有关AMD设备通过导出CSV文件和IBIS模型&#xff0c;与PCB或系统设计者进行引脚连接。根据PCB或设计规范的变化&#xff0c;您可能需要将引脚重新导入为如定义和配置I/O端口中所述。完成I/O和时钟中的…

如何在 Mac 中运行 Office 办公软件

虽然 Office 软件也有 Mac 版本的&#xff0c;但是有蛮多小伙伴用起来还是感觉不得劲&#xff0c;毕竟接触了太久的 Windows&#xff0c;所以想要使用 Windows 版本的 Office 软件。 今天就给大家介绍一下怎么在 Mac 电脑中运行 Windows 版本的办公软件&#xff0c;在这里就需…

【Qt】—— Qt Creator 创建项目

目录 &#xff08;一&#xff09;Qt Creator概览 &#xff08;二&#xff09;使⽤Qt Creator新建项⽬ &#xff08;一&#xff09;Qt Creator概览 从开始菜单或者快捷⽅式打开Qt Creator集成开发环境&#xff0c;启动之后看到类似下⾯的界⾯&#xff1a; 【解释说明】 菜单栏…

0101appscan安装与使用入门-扫描-信息收集

1 简介 HCL AppScan&#xff08;原IBM Security AppScan&#xff09;是原IBM的Rational软件部门的一组网络安全测试和监控工具&#xff0c;2019年被HCL技术公司收购。AppScan旨在在开发过程中对Web应用程序的安全漏洞进行测试[1]。该产品学习每个应用程序的行为&#xff0c;无…

杂题——试题-算法训练-P0604-runaround数

分析&#xff1a; 题目有三个关键点&#xff1a; 一&#xff1a;结束时&#xff0c;回到起始位置&#xff08;比较结束时和起始时的下标位置是否相同&#xff09;二&#xff1a;该整数的所有数字都必须遍历一遍&#xff0c;且只能遍历一遍&#xff08;把遍历过的数字做个标记&a…

牛客,OR36 链表的回文结构,快慢指针和反转链表的实践

链表的回文结构_牛客题霸_牛客网 (nowcoder.com) 还是比较简单的&#xff0c;主要分为三个步骤&#xff0c;两种需掌握的函数实现 目录 主要思路过程&#xff0c;1&#xff0c;找到中间结点&#xff0c;2&#xff0c;反转中间结点往后的结点&#xff0c;3&#xff0c;遍历比…

如何将AI智能监控应用在物业中打造智慧物业系统

方案背景 随着视频智能化发展&#xff0c;仅靠人力管理的传统物业已然成为历史&#xff0c;为了降低人工成本&#xff0c;实现精细化管理&#xff0c;人工智能的帮助必不可少&#xff0c;旭帆科技AI智能监控系统在物业中可以用于打造智慧物业系统&#xff0c;提升物业管理的效…

MacBook安装虚拟机VMware Fusion

MacBook安装虚拟机VMware Fusion 官方下载地址: https://customerconnect.vmware.com/cn/downloads/info/slug/desktop_end_user_computing/vmware_fusion/11_0 介绍 之前的版本都要收费,现在出了对个人免费的版本, 棋哥给的破解版的版本是8,升级系统后用不了了. 官方去下载…

VR全景技术如何运用在文旅展示,VR全景技术对景区有哪些好处

引言&#xff1a; 随着科技的不断进步和社会的不断发展&#xff0c;VR全景技术越来越受到人们的关注。在文化旅游行业中&#xff0c;VR全景技术的应用为景区提供了全新的展示方式和体验内容&#xff0c;极大地丰富了游客的文化旅游体验。那么VR全景技术能给文旅展示带来哪些好…

AI的安全应答之道

作者&#xff1a;统信UOS技术团队 2023,随着各种大语言模型的爆发&#xff0c;整个AI生态正处于从决策式AI进化到生成式AI的进程中。各类AI模型和AI应用层出不穷&#xff0c;也随之带来了与AI相关的各类潜在风险。AI开发和使用过程中的风险防范和治理&#xff0c;成为了不可忽…

020 switch多选择结构

什么是switch多选择结构 switch语句中的变量类型为char的示例 char grade A; switch (grade){case A:System.out.println("成绩为A");break;case B:System.out.println("成绩为B");break;case C:System.out.println("成绩为C");break;case D:S…

022 do while循环

什么是do while循环 int i 0; do {System.out.println(i);i; } while (i < 100); 具体使用场景 int i; Scanner scanner new Scanner(System.in); do {System.out.print("请输入一个整数&#xff0c;如果为负数则结束循环&#xff1a;");i scanner.nextInt(…

去中心化治理时代——SunrayDAO正式发布用户自治模式规范提案

去中心化自治组织&#xff08;DAO&#xff09;从概念的提出再到市场不断检验发展至今&#xff0c;为社群集体决策提供了一个透明和去中心化的治理模式&#xff0c;区块链行业技术的迭代&#xff0c;各类项目和平台对DAO治理模式的探索从未停止&#xff0c;DAO这个象征着区块链精…

Matlab数字图像处理——图像复原与滤波算法应用方法

图像处理领域一直以来都是计算机科学和工程学的一个重要方向&#xff0c;图像复原则是其中一个重要的研究方向之一。图像复原旨在通过运用各种滤波算法&#xff0c;对图像进行去噪、恢复和改善&#xff0c;以提高图像的质量和可视化效果。在本文中&#xff0c;我们将介绍如下内…