当前位置: 首页 > news >正文

前端对于深拷贝和浅拷贝的应用和思考

浅拷贝

浅拷贝 : 浅拷贝是指对基本类型的值拷贝,以及对对象类型的地址拷贝。它是将数据中所有的数据引用下来,依旧指向同一个存放地址,拷贝之后的数据修改之后,也会影响到原数据的中的对象数据。最简单直接的浅拷贝就是直接赋值,如:let obj = xxx或者Array.prototype.slice()

深拷贝

深拷贝:指复制并创建一个一模一样的对象,不共享内存,修改新对象,旧对象保持不变。

应用场景:常用的场景就是表格编辑对话框回显,你需要深拷贝当前行数据赋值上去,否则当你修改编辑框的数据,你会发现表格的对应行的数据也会跟着修改。

Object.assign()

//用法
let obj = {a:'a',b:'b'}
let newObj = Object.assign({},obj) 

用法很简单,可以拷贝复杂类型。但是有限制,首先它只能用于对象的拷贝,其次它是只能深拷贝第一层,第二层开始就是浅拷贝了(一深二浅),不能拷贝循环引用类型。

实验代码:

let obj = {date:new Date(),regexp:new RegExp(),err:new Error(),fn:()=>{console.log(222)},un:undefined,nan:NaN,c:{fn:new Date()}
}
// obj.a=obj //循环引用类型不能拷贝,报错,大概意思是说要转为json格式
let arr = Object.assign({},obj)
console.log('obj',obj)
console.log('arr',arr) 

实验截图:

拓展运算符

拓展运算符的功能很强大,可以用于对象数组,可以拷贝对象和数组,可以将数组转换为参数序列,复制数组,合并数组等。这里主要讲的拷贝功能,其他功能读者有兴趣可以另行寻找文章了解。

//扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
let obj = {a:'a',b:'b'}
let arr = [1,2,3]
let newObj = {...obj}
let newArr = [...arr] 

用法也是很简单,也可以拷贝复杂类型。但是也有限制。仅作为第一层是为深拷贝,可以拷贝复杂类型,对于数组和对象都一样,对于第二层极其以后的值,扩展运算符将不能对其进行打散扩展,也不能对其进行深拷贝,即拷贝后和拷贝前第二层中的对象或者数组仍然引用的是同一个地址,其中一方改变,另一方也跟着改变。

实验代码:

//这里只贴上对于数组的操作,对象的操作跟上面的差不多,拓展运算符的拷贝也不能拷贝循环引用的数据
let arr = [1,2,3,[2,3,[4]]]
let newArr = [...arr]
console.log('arr',arr)
console.log('newArr',newArr) 

实验截图

JSON.parse(JSON.stringify(obj))

这种方式是我在项目中用的最多的方法。但是局限性比前两个还多。它只适用于纯数据json对象的深度克隆。

//用法
let obj = {a:'a'}
let json = JSON.parse(JSON.stringify(obj)) 

用法简单,局限性很多,目前我所了解的大概有这些:

1.如果obj里面存在时间对象,JSON.parse(JSON.stringify(obj))之后,时间对象变成了字符串。
2.如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象。
3.如果obj里有函数,undefined,则序列化的结果会把函数, undefined丢失。
4.如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null。
5.JSON.stringify()只能序列化对象的可枚举的自有属性。如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor。
6.如果对象中存在循环引用的情况也无法正确实现深拷贝。

实验代码:

//定义一个构造函数function Person(age){this.age = age}let obj = {date: new Date(),regexp: new RegExp(),err: new Error(),fn: () => {console.log(222)},un: undefined,nan: NaN,c: {fn: new Date()},age:new Person(20)}obj.a = obj //无法拷贝循环引用的数据,报错,大概意思是说要转为json格式let json = JSON.parse(JSON.stringify(obj))console.log('obj', obj)console.log('json', json) 

实验截图:

使用较为完整的深拷贝

Lodash

建议使用Lodash库,这是一个很强大的库,里面有各种各样的封装方法,十分强大。

1.安装npm i lodash2.组件引入import _ from 'lodash'3.使用const form = _.cloneDeep(拷贝的对象) 

使用JQ

通过jq的$.extend()实现深拷贝,当extend内的第一个参数为true时,实现的是深拷贝,false是浅拷贝。

自定义方法

这里的方法是从网上搬运过来的,我之前面试的时候就背这个,个人觉得挺全面的

function deepClone(obj, cache = new WeakMap()) {if (typeof obj !== 'object') return obj //普通类型,直接返回if (obj === null) return objif (cache.get(obj)) return cache.get(obj)//防止循环引用,程序进入死循环if (obj instanceof Date) return new Date(obj)//返回时间格式if (obj instanceof RegExp) return new RegExp(obj)//返回正则if (typeof obj === 'symbol') return Symbol(obj.description)	// 处理 Symbol//找到所属原型上的constructor,所属原型上的constructor指向点前对象的构造函数let cloneObj = new obj.constructor()// console.log(cloneObj)cache.set(obj, cloneObj)//缓存拷贝的对象,用于处理循环引用的情况for (let key in obj) {//hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。if (obj.hasOwnProperty(key)) {// console.log(key)cloneObj[key] = deepClone(obj[key], cache)//递归拷贝}}return cloneObj}//测试const obj = { name: 'Jack', address: { x: 100, y: 200 }, a: [1, 2, 3, 4], b: Symbol('22') }obj.a = obj//循环引用,会一直嵌套const newObj = deepClone(obj)console.log('obj', obj)console.log('newObj', newObj) 

总结:学艺不精,请多多担待,写下这篇文章主要是为了记录自己的成长,如果能顺便帮到你那笔者会很开心。如果有大佬有宝贵的意见可以指导,将万分感谢(* ̄︶ ̄)!

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

相关文章:

前端对于深拷贝和浅拷贝的应用和思考

浅拷贝 浅拷贝 : 浅拷贝是指对基本类型的值拷贝,以及对对象类型的地址拷贝。它是将数据中所有的数据引用下来,依旧指向同一个存放地址,拷贝之后的数据修改之后,也会影响到原数据的中的对象数据。最简单直接的浅拷贝就…...

Java基础常见面试题(三)

String 字符型常量和字符串常量的区别? 形式上: 字符常量是单引号引起的一个字符,字符串常量是双引号引起的若干个字符; 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算;字符串常量代表一个地址值…...

C++设计模式(13)——装饰模式

亦称: 装饰者模式、装饰器模式、Wrapper、Decorator 意图 装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 问题 假设你正在开发一个提供通知功能的库, 其他程序可使用它向用户发…...

ESP-01S通过AT指令上报数据到阿里云物模型

ESP-01S使用AT指令上报数据到阿里云物模型 上篇文章介绍了如何用AT指令连接阿里云并进行通信:https://blog.csdn.net/weixin_46251230/article/details/128995530 但最终需要将传感器数据上报到云平台显示,所以需要建立阿里云物模型 阿里云平台建立物…...

【强化学习】马尔可夫决策过程MDP

1.马尔可夫决策过程MDP 1.1 MDP五元组 MDP<S,A,P,R,γ>MDP<\mathcal{S},\mathcal{A},\mathcal{P},\mathcal{R},\mathcal{\gamma}>MDP<S,A,P,R,γ>&#xff0c;其中&#xff1a; S\mathcal{S}S&#xff1a;状态空间A\mathcal{A}A&#xff1a;动作空间P\mathc…...

刘润:五维思考,让你站得更高、看得更远

原标题&#xff1a;刘润&#xff1a;五维思考&#xff0c;让你站得更高、看得更远 前言&#xff1a;遇到问题时&#xff0c;有的人很快就能想明白&#xff0c;有的人需要很久才能想明白&#xff0c;还有的人始终都想不明白。 而且&#xff0c;那些很快就能想明白的人&#xff0…...

从运维角度看微服务 k8s部署微服务【偏理论】【AL】

从运维角度看微服务 & 部署微服务【偏理论】 1、微服务的特点 服务组件化&#xff1a; 每个服务独立开发、部署&#xff0c;有效避免一个服务的修改引起整个系统重新部署。 技术栈灵活&#xff1a; 约定通信方式&#xff0c;使得服务本身功能实现对技术要求不再那么敏感。…...

专题 | 防抖和节流

一 防抖&#xff1a;单位时间内&#xff0c;频繁触发事件&#xff0c;只执行最后一次 场景&#xff1a;搜索框搜索输入&#xff08;利用定时器&#xff0c;每次触发先清掉以前的定时器&#xff0c;从新开始&#xff09; 节流&#xff1a;单位时间内&#xff0c;频繁触发事件&…...

C++入门:重载运算符和重载函数

C 允许在同一作用域中的某个函数和运算符指定多个定义&#xff0c;分别称为函数重载和运算符重载。重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明&#xff0c;但是它们的参数列表和定义&#xff08;实现&#xff09;不相同。当您调用一个重载函…...

conda 新建虚拟环境 等等

1&#xff1a;conda create -n env_name package_name #创建名为env_name的新环境&#xff0c;并在该环境下安装名为package_name 的包&#xff0c;例如&#xff1a;conda create -n Arg python3.8 # 创建名字为Arg python为3.8版本的虚拟环境2&#xff1a; conda activate env…...

【C++:STL之栈和队列 | 模拟实现 | 优先级队列 】

目录 1. stack的介绍和使用 1.1 stack的介绍 1.2 stack的使用 2 栈的模拟实现 3 queue的介绍和使用 3.1 queue的介绍 3.2 queue的使用 4 queue的模拟实现 5 deque的介绍 5.1deque的原理介绍 5.2 deque的缺陷 5.3 为什么选择deque作为stack和queue的底层默认容器 6 p…...

基于SpringBoot+Vue的疫苗预约管理系统(Java项目)

【辰兮要努力】&#xff1a;hello你好我是辰兮&#xff0c;很高兴你能来阅读&#xff0c;昵称是希望自己能不断精进&#xff0c;向着优秀程序员前行&#xff01; 博客来源于项目以及编程中遇到的问题总结&#xff0c;偶尔会有读书分享&#xff0c;我会陆续更新Java前端、后台、…...

华为OD机试 - 计算网络信号(Python),真题含思路

计算网络信号 题目 网络信号经过传递会逐层衰减,且遇到阻隔物无法直接穿透,在此情况下需要计算某个位置的网络信号值。 注意:网络信号可以绕过阻隔物 array[m][n] 的二维数组代表网格地图,array[i][j] = 0 代表 i 行 j 列是空旷位置;array[i][j] = x ( x 为正整数)代表 i …...

【Spring】注解实现IOC操作,你理解了吗?

作者&#xff1a;狮子也疯狂 专栏&#xff1a;《spring开发》 坚持做好每一步&#xff0c;幸运之神自然会驾凌在你的身上 专栏推荐&#xff1a;写文章刚刚起步&#xff0c;各个专栏的知识点后续会补充完善&#xff0c;不断更新好文&#xff0c;希望大 家支持一下。 专栏名字El…...

微搭低代码从入门到精通01-总体介绍

在过去我们开发小程序&#xff0c;要学习各类知识。比如前端知识、后端知识、服务器知识及各种中间件及数据库的知识。 要想学会这些知识&#xff0c;既需要投入大量的学习时间&#xff0c;而且要经过相当的实践才可以掌握。 如果立志从事开发行业&#xff0c;投入精力去学习…...

类的继承

类的继承&#xff1a;一个类继承另一个类&#xff0c;自动拥有这个类的属性和方法&#xff0c;类似于包含与被包含的关系。被继承的类称为父类--子类则是继承父类的类。一个父类可以有多个子类&#xff1b;一个子类可以有多个父类&#xff08;多继承&#xff09;问题创建子类时…...

应用场景一:西门子PLC通过桥接器连接MQTT服务器

应用场景描述&#xff1a; 云平台、MES等数据采集、设备管理系统&#xff0c;需要通过MQTT的方式&#xff0c;上传和下发数据&#xff0c;MQTT服务器可以获取PLC的实时状态数据&#xff0c;也可以下发控制指令。桥接器提供4G、WIFI和有线三种连接方式。 网络拓扑&#xff1a;…...

计算机组成原理(四)

1.理解存储器的分类方法&#xff1b;理解存储器的层次结构&#xff1b;熟悉存储器的几个技术指标&#xff08;主要是存储容量、存取时间、存取周期、存储器带宽等&#xff09;&#xff1b; 存储器分类方法&#xff1a;   按与CPU的连接和功能分类&#xff1a;     主存储…...

状态机设计举例

⭐本专栏针对FPGA进行入门学习&#xff0c;从数电中常见的逻辑代数讲起&#xff0c;结合Verilog HDL语言学习与仿真&#xff0c;主要对组合逻辑电路与时序逻辑电路进行分析与设计&#xff0c;对状态机FSM进行剖析与建模。 &#x1f525;文章和代码已归档至【Github仓库&#xf…...

Kubernetes1.25中Redis单机和集群部署实例二

1、概述我们知道在 Kubernetes 容器编排平台中, 我们可以非常方便的进行应用的扩容缩, 同时也能非常方便的进行业务的迭代&#xff0c;本章主要讲解在Kubernetes1.25搭建Redis单实例和Redis集群主从同步的环境流程步骤, 如果是高频访问重要的线上业务我们最好是部署在物理机器上…...

【STM32】【HAL库】遥控关灯0 概述

相关连接 【STM32】【HAL库】遥控关灯0 概述 【STM32】【HAL库】遥控关灯1主机 【STM32】【HAL库】遥控关灯2 分机 【STM32】【HAL库】遥控关灯3 遥控器 需求 家里有几个房间,开关距离床都挺远的 睡觉想要关灯的时候需要下床 因此设计了本次项目 需要满足以下要求: 可以控…...

C语言学习笔记(三): 选择结构程序设计

if语句 if(){} if (a1){printf("hehe");} //单独一个ifif(){}else{} int a 1, b 2;if (a b) {printf("haha"); //if else}else{printf("hehe");}if(){}else if(){} int a 1, b 2;if (a b) {printf("haha");}else if (a …...

图----无向图

1.定义 图的定义&#xff1a;图是由一组顶点和一组能够将两个顶点相连的边组成 边&#xff1a;edge 顶点&#xff1a;vertex 连通图&#xff1a;如果从任意一个顶点都存在一条路径到达另外一个任意顶点&#xff0c;我们称这幅图是连通图。 非连通图&#xff1a;由若干连通的…...

【C++1】函数重载,类和对象,引用,/string类,vector容器,类继承和多态,/socket,进程信号

文章目录1.函数重载&#xff1a;writetofile()&#xff0c;Ctrue和false&#xff0c;C0和非02.类和对象&#xff1a;vprintf构造函数&#xff1a;对成员变量初始化析构函数&#xff1a;一个类只有一个&#xff0c;不允许被重载3.引用&#xff1a;C中&取地址&#xff0c;C中…...

JetpackCompose从入门到实战学习笔记8—ConstraintLayout的简单使用

JetpackCompose从入门到实战学习笔记8—ConstraintLayout的简单使用 1.简介&#xff1a; Compose 中的 ConstraintLayout ConstraintLayout 是一种布局&#xff0c;让您可以相对于屏幕上的其他可组合项来放置可组合项。它是一种实用的替代方案&#xff0c;可代替使用多个已嵌…...

Spring Boot 快速入门(绝对经典)

目录 1、理论概述 1.1、什么是Spring Boot? 1.2、Spring Boot的特点 1.3、开发环境 2、实战——创建和配置项目 2.1、Spring Boot项目创建的两种方式 2.1.1、方法一&#xff1a;通过网站构建项目 2.1.2、使用Spring Initializr创建&#xff08;推荐&#xff09; 2.2、…...

golang context上下文

文章目录一、为什么需要context二、context 接口三、Background 方法四、 with 系列函数1、WithCancel 方法2、WithDeadline 方法3、WithTimeout 方法4、WithValue 方法五、使用注意事项一、为什么需要context 在 Go http包的Server中&#xff0c;每一个请求在都有一个对应的 …...

Linux---Linux是什么

Linux 便成立的核心网站&#xff1a; http://www.kernel.org Linux是什么 Linux 就是一套操作系统 Linux 就是核心与系统呼叫接口那两层 软件移植&#xff1a;如果能够参考硬件的功能函数并据以修改你的操作系统程序代码&#xff0c; 那经过改版后的操作系统就能够在另一个硬…...

C语言(Tgmath.h库(C99),exit和atexit)

一.Tgmath.h库&#xff08;C99&#xff09; C99标准提供得tgmath.h头文件定义了泛型类型宏。比如在math.h中为一个函数定义了3中类型(float,double和long double)的版本&#xff0c;那么tgmath.h文件就创建一个泛型类型宏&#xff0c;与原来的float,double和long double版本的…...

LeetCode 刷题系列 -- 739. 每日温度

给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。示例 1:输入:temperatures …...

网 公司/整站seo优化公司

Open3D点云去除质心&#xff1a;如何高效处理点云数据&#xff1f; 在计算机视觉领域&#xff0c;点云数据处理是一个非常重要的任务。对于大规模的点云数据集&#xff0c;如何高效地去除其中的质心是一个关键问题。Open3D作为一个开源的计算几何库&#xff0c;提供了多种方法…...

合肥网站建设制作/百度浏览器电脑版

PPT 使用经验少, 直接使用模板发现每一张都有动画, 花里胡哨… 而动画只能一张一张去删除, 若 PPT 页数多会比较麻烦. 此时可选 幻灯片放映 ➡ 放映时不加动画 至此, 烦人的动画消失~...

给网站做压力测试/百度竞价推广思路

多线程之BackgroundWorker组件 : 点击打开链接 C# 使用BackgroundWorker实现WinForm异步 : 点击打开链接 c# BackGroundWorker 多线程操作的小例子 : 点击打开链接 在BackgroundWorker运行过程中关闭窗体 点击打开链接 backgroundworker与Thread区别 点击打开链接 C#运行后…...

落地页需要建网站吗/怎么制作网页广告

http://www.bitbug.net/ 图标要为ICO格式的&#xff0c;把你的图传到这个网上去&#xff0c;不到两秒它就会让你下那个图的ICO格式的图&#xff0c;就可以用了 但设置后图标的清晰度一般...

竹子建站登录/营销网站

注 对象与槽理解 //第一个参数lineEdit是激发事件对象,信号中的方法必须在对象中存在&#xff0c;并在对象类头文件signals下定义&#xff0c;//第二个参数信号&#xff0c;//第三个参数this是槽方法所属类的对象&#xff0c;且必须在对象类的头文件的slots下定义//第四个参数槽…...

西宁哪家公司做网站/市场营销实务

今天记录常用的几种合并数组的方法&#xff0c;除了 array_merge() 和 array_merge_recursive() 两个数组外&#xff0c;还有一个加号“”&#xff0c;也都能实现合并数组的上的&#xff0c;但各有差别。加号 “”使用加号 “” 这个数组操作符能很方便的将多个数组进行合并&am…...