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

前端之深拷贝

前提:

就是在实际开发中,我有一个编辑的弹窗,可以查看和编辑,因为弹窗里面是一个步骤条,点击下一步就要向对应的接口发送请求,考虑到就比如我点击下一步,此次表箱信息其实不需要修改,我要修改的是控制器的信息,那么点击下一步发送请求其实是没有必要的,我就考虑到了进行比对,如果没有变化就直接下一步,不发送请求

我的想法是,在点击编辑时,把变化前的值给一个变量(旧值),然后在点击下一步用现在的值和旧值进行对比

const editDataBox = ref<any>({});
const initialFormData = ref<any>({});
//编辑
const handleEdit = async (data: any) => {editVisible.value = true;
//在弹窗弹出的时候,把传递过来的值给一个变量initialFormData.value=data
editDataBox.value = data;
....
}
const isFormDataEqual = (formData1: any, formData2: any) => {return JSON.stringify(formData1) === JSON.stringify(formData2);
};
//下一步
const editNext = () => {switch (editCurrent.value) {case 1:const formDataChanged = !isFormDataEqual(editDataBox.value, initialFormData.value);if (formDataChanged) {
...
}else{editCurrent.value += 1;
}
}

这是我刚开始的想法,原本我以为就是initialFormData这个值不会变化,然后我发现表单值变化了也没有发送请求,我就输出formDataChanged这个值,发现每次都是false,进而输出initialFormData它的值,就发现它既然是变化后的值,我就想问题在哪里,原因是:

在 JavaScript 中,当你将一个对象赋值给另一个变量时,实际上是将对象的引用赋值给了这个变量,而不是对象本身的拷贝。这意味着,如果你修改了其中一个变量所引用的对象,另一个变量也会受到影响,因为它们引用的是同一个对象。

在你的代码中,initialFormDataeditDataBox 都是使用 ref 创建的响应式对象。当你在 handleEdit 函数中将 data 赋值给 initialFormData.valueeditDataBox.value 时,它们实际上是引用了同一个对象。

因此,当你修改 editDataBox.value 后,initialFormData.value 也会受到影响,因为它们引用的是同一个对象。

为了避免这种情况,你需要确保 initialFormDataeditDataBox 引用的是不同的对象,而不是同一个对象的引用。这就是为什么需要进行深拷贝的原因,因为深拷贝会创建一个新的对象,其值与原始对象相同,但是引用不同,这样就可以独立地修改新对象而不影响原始对象。

我的解决办法是使用 JSON.parse() 和 JSON.stringify() 进行深拷贝,修改后的代码是,加了一个deepCopy函数进行深拷贝

JSON.parse() 和 JSON.stringify()

const editDataBox = ref<any>({});
const initialFormData = ref<any>({});
const deepCopy = (obj: any) => {return JSON.parse(JSON.stringify(obj));
};
//编辑
const handleEdit = async (data: any) => {editVisible.value = true;initialFormData.value = deepCopy(data);
editDataBox.value = data;
....
}
const isFormDataEqual = (formData1: any, formData2: any) => {return JSON.stringify(formData1) === JSON.stringify(formData2);
};
//下一步
const editNext = () => {switch (editCurrent.value) {case 1:const formDataChanged = !isFormDataEqual(editDataBox.value, initialFormData.value);if (formDataChanged) {
...
}else{editCurrent.value += 1;
}
}

使用 Object.assign():

这个方法只能实现浅拷贝,但如果对象的结构比较简单且不包含嵌套对象,也可以考虑使用它 

const deepCopy = (obj) => {return Object.assign({}, obj);
};

 使用递归:

可以编写一个递归函数来遍历对象的所有属性,并对每个属性进行拷贝。这需要一些额外的代码,但也是一个有效的方法。

const deepCopy = (obj) => {if (typeof obj !== 'object' || obj === null) {return obj;}let newObj = Array.isArray(obj) ? [] : {};for (let key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = deepCopy(obj[key]);}}return newObj;
};

使用 Lodash 库 

Lodash 提供了 _.cloneDeep() 方法,可以实现对象的深拷贝。这是一个非常流行且易于使用的方法。

const _ = require('lodash');// 使用 _.cloneDeep() 进行深拷贝
const deepCopy = (obj) => {return _.cloneDeep(obj);
};

深拷贝在编程中几个重要的优势和应用场景: 

  1. 数据独立性: 深拷贝创建了原始对象的完全独立副本,这意味着修改拷贝后的对象不会影响原始对象。这对于需要在多个地方使用同一份数据,但又需要独立修改数据的情况非常有用。

  2. 避免引用问题: 在 JavaScript 中,如果你简单地将一个对象赋值给另一个变量,实际上是将对象的引用传递给了新变量。这意味着如果你修改了新变量中的对象,原始对象也会受到影响。深拷贝可以避免这种问题,因为它创建了一个完全独立的对象,不会共享内存地址。

  3. 数据传递: 在许多情况下,你可能需要将数据传递给其他函数或组件,并且希望确保传递的是数据的副本而不是引用。深拷贝可以确保你传递的是数据的完整副本,而不会影响原始数据。

  4. 数据比较: 当需要比较两个对象是否相等时,深拷贝可以确保比较的是对象的值而不是引用。这在进行单元测试、数据验证或其他需要比较对象的场景中非常有用。

总的来说,深拷贝是一种保护数据完整性和独立性的重要工具,可以帮助避免由于对象共享引起的意外行为,并确保数据在不同部分之间的传递和修改时保持一致。

你学会了吗?

嗯,可能有的朋友还不太了解JSON.parse() 和 JSON.stringify()?我也是一知半解。

我在想应该写在另一篇文章还是写在这里?emmm,还是重新写一个吧,可以点击跳转

最后,我也是刚入行时间不长的前端,如果有写的有什么问题欢迎指正与交流。

相关文章:

前端之深拷贝

前提&#xff1a; 就是在实际开发中&#xff0c;我有一个编辑的弹窗&#xff0c;可以查看和编辑&#xff0c;因为弹窗里面是一个步骤条&#xff0c;点击下一步就要向对应的接口发送请求&#xff0c;考虑到就比如我点击下一步&#xff0c;此次表箱信息其实不需要修改&#xff0…...

2024年 Java 面试八股文——SpringCloud篇

目录 1.Spring Cloud Alibaba 中的 Nacos 是如何进行服务注册和发现的&#xff1f; 2.Spring Cloud Alibaba Sentinel 的流量控制规则有哪些&#xff1f; 3.Spring Cloud Alibaba 中如何实现分布式配置管理&#xff1f; 4.Spring Cloud Alibaba RocketMQ 的主要特点有哪些&…...

linux C语言Makefile

ChatGPT 在Linux中使用Makefile来自动化C语言项目的构建过程是很普遍的实践。Makefile是一个包含了一系列构建目标及如何构建这些目标的依赖和规则的文本文件。 一个基本的Makefile例子可能会像这样&#xff1a; # 定义编译器 CCgcc# 定义编译选项 CFLAGS-I.# 定义可执行文件…...

pgvector扩展在IvorySQL Oracle兼容模式下的应用实践

向量数据库是生成式人工智能(GenAI)的关键组成部分。作为PostgreSQL的重要扩展&#xff0c;pgvector支持高达16000维的向量计算能力&#xff0c;使得PostgreSQL能够直接转化为高效的向量数据库。 IvorySQL基于PostgreSQL开发&#xff0c;因此它同样支持添加pgvector扩展。在Ora…...

c++ 线程概述

C中的线程是并发编程的重要组成部分&#xff0c;它允许程序同时执行多个任务。以下是对C线程的概述&#xff1a; 基本概念&#xff1a; 并发&#xff1a;意味着两个或多个任务同时执行。在单核CPU上&#xff0c;由于只有一个CPU&#xff0c;某一时刻只能执行一个任务&#xff0…...

纯血鸿蒙APP实战开发——短视频切换实现案例

短视频切换实现案例 介绍 短视频切换在应用开发中是一种常见场景&#xff0c;上下滑动可以切换视频&#xff0c;十分方便。本模块基于Swiper组件和Video组件实现短视频切换功能。 效果图预览 使用说明 上下滑动可以切换视频。点击屏幕暂停视频&#xff0c;再次点击继续播放…...

36.Docker-Dockerfile自定义镜像

镜像结构 镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。 镜像是分层机构&#xff0c;每一层都是一个layer BaseImage层&#xff1a;包含基本的系统函数库、环境变量、文件系统 EntryPoint:入口&#xff0c;是镜像中应用启动的命令 其他&#xff1a;在…...

【webrtc】MessageHandler 4: 基于线程的消息处理:以Fake 收发包模拟为例

G:\CDN\rtcCli\m98\src\media\base\fake_network_interface.h// Fake NetworkInterface that sends/receives RTP/RTCP packets.虚假的网络接口,用于模拟发送包、接收包单纯仅是处理一个ST_RTP包 消息的id就是ST_RTP 类型,– 然后给到目的地:mediachannel处理: 最后消息消…...

C#运算符“/”使用方法

C#中&#xff0c;当需要对两个整数进行除法运算时&#xff0c;结果会被截断为整数部分&#xff0c;即使结果本应是一个小数。这是因为整数除法会丢弃小数部分&#xff0c;只保留整数部分。 要想保留小数部分&#xff0c;需要将至少其中一个操作数转换为float、double或者 deci…...

虚拟机网络桥接模式无法通信,获取到的ip为169.254.X.X

原因&#xff1a;VMware自动选择的网卡可能不对 解决&#xff1a;编辑-虚拟网络编辑器-更改桥接模式-选择宿主机物理网卡&#xff0c;断开虚拟机网络连接后重新连接即可...

【数据结构】初识数据结构

引入&#xff1a; 哈喽大家好&#xff0c;我是野生的编程萌新&#xff0c;首先感谢大家的观看。数据结构的学习者大多有这样的想法&#xff1a;数据结构很重要&#xff0c;一定要学好&#xff0c;但数据结构比较抽象&#xff0c;有些算法理解起来很困难&#xff0c;学的很累。我…...

相机知识的补充

一&#xff1a;镜头 1.1MP的概念 相机中MP的意思是指百万像素。MP是mega pixel的缩写。mega意为一百万&#xff0c;mega pixel 指意为100万像素。“像素”是相机感光器件上的感光最小单位。就像是光学相机的感光胶片的银粒一样&#xff0c;记忆在数码相机的“胶片”&#xff…...

在Linux操作系统中实现磁盘开机自动挂载

当一个分区创建好&#xff0c;然后文件系统创建完毕之后&#xff0c; 需要使用mount命令将分区挂载到空目录上&#xff0c;这个挂载关系是临时的&#xff0c;也就是说当重启机器的时候&#xff0c;硬盘分区于空目录之间的挂载关系就会解除。 磁盘于目录之间的挂载关系断开意味…...

单片机编程实例400例大全(100-200)

今天继续分享单片机编程实例第100-200例。 今天的实例会比前面100复杂一些&#xff0c;我大概看了下&#xff0c;很多都具备实际产品的参考价值。 今天继续分享单片机编程实例第100-200例。 今天的实例会比前面100复杂一些&#xff0c;我大概看了下&#xff0c;很多都具备实际…...

新兴游戏引擎Godot vs. 主流游戏引擎Unity和虚幻引擎,以及版本控制工具Perforce Helix Core如何与其高效集成

游戏行业出现一个新生事物——Godot&#xff0c;一个免费且开源的2D和3D游戏引擎。曾经由Unity和虚幻引擎&#xff08;Unreal Engine&#xff09;等巨头主导的领域如今迎来了竞争对手。随着最近“独特”定价模式的变化&#xff0c;越来越多的独立开发者和小型开发团队倾向于选择…...

Leetcode—1652. 拆炸弹【简单】

2024每日刷题&#xff08;127&#xff09; Leetcode—1652. 拆炸弹 实现代码 class Solution { public:vector<int> decrypt(vector<int>& code, int k) {int codeSize code.size();vector<int> ans(codeSize, 0);if(k 0) {return ans;}if(k > 0)…...

JAVASE---抽象类相关

instanceof 和类型转换 System.out.println(X instanceof Y );主要看X与Y之间是否存在父子&#xff08;继承&#xff09;关系&#xff0c;如果存在则编译可完成&#xff0c;否则无法 进行编译。 1.父类引用指向子类的对象 2.把子类转换为父类&#xff0c;向上转型; 3.把父类转…...

深入理解C++中的inline函数

在C编程中&#xff0c;我们经常会遇到inline关键字&#xff0c;它用于修饰函数&#xff0c;以建议编译器将该函数的调用替换为函数体的直接拷贝。这就是inline函数的基本概念。然而&#xff0c;inline函数并非真正意义上的函数&#xff0c;而只是一种"在调用点插入函数体&…...

Rust 动态数组Vector

导航 一、动态数组是什么&#xff0c;怎么用1、动态数组Vector是什么2、动态数组怎么用&#xff08;1&#xff09;创建动态数组&#xff08;2&#xff09;尾部追加元素&#xff08;3&#xff09;尾部删除元素&#xff08;4&#xff09;删除指定位置元素&#xff08;5&#xff0…...

Linux主机重启后报错:[FAILED] Failed to start Switch Root.

一、问题描述 某次云主机因计费问题&#xff0c;导致批量重启&#xff0c;重启后发现某台云主机竟进入紧急救援模式&#xff08;emergency模式&#xff09;&#xff0c;如下所示&#xff1a; 二、原因及处理 1&#xff09;原因&#xff1a;加载根分区失败&#xff0c;导致无…...

git--.gitignore--使用/详解/实例

简介 本文介绍git的.gitignore忽略文件的用法。 项目中并不是所有文件都需要保存到版本库中的&#xff0c;例如“target”目录及目录下的文件就可以忽略。 忽略某个文件&#xff08;不提交到版本库的方法&#xff09;&#xff1a;在Git工作区的根目录下创建一个.gitignore文件…...

初识java——javaSE(2)--运算符与逻辑控制【求个关注】

文章目录 一 运算符1.1 算术运算符当两个不同类型的值相加时&#xff1a;/ 运算符%运算符 1.2 关系运算符1.3 逻辑运算符短路&#xff1a;逻辑非 1.4 位运算符&|^位运算符当作逻辑运算符中使用 ~>><<>>> 1.5 赋值运算符1.6 三目运算符 二 逻辑控制if语…...

JAVA前端快速入门基础_javascript入门(02)

写在前面:本文用于快速学会简易的JS&#xff0c;仅做扫盲和参考作用 1.JavaScript函数 什么是函数:执行特定任务的代码块 1.1定义&#xff1a; 使用function来进行定义(类似于python里面的def 或者java和c里面的void&#xff0c;int这些返回类型开头)。定义规则如下: func…...

【热门话题】ElementUI 快速入门指南

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 ElementUI 快速入门指南环境准备安装 ElementUI创建 Vue 项目安装 ElementUI 基…...

webpack4和webpack5区别4---自动清除打包目录

webpack4 自动清除打包目录 需要使用clean-webpack-plugin插件 const {CleanWebpackPlugin} require(clean-webpack-plugin); module.exports {plugins: [new CleanWebpackPlugin()} } webpack5 自动清除打包目录 module.exports {output: {clean: true} }...

npm许可证检查

node开发做项目&#xff0c;很少有人去纯手工打造&#xff0c;大多是采用一些开源框架&#xff0c;还会使用前人做好的轮子&#xff0c;所以咱们的项目文件里&#xff0c;除了自己编写的js文件&#xff0c;还会带有一些拿来主义的npm模块&#xff0c;从其他开源发布网站上下载的…...

利用AI大模型和Echarts 绘制知识图谱,实现文本信息提取和图数据库操作

引言 随着信息时代的到来&#xff0c;海量的文本数据成为了我们获取知识的重要来源。然而&#xff0c;如何从这些文本数据中提取出有用的信息&#xff0c;并将其以可视化的方式展示出来&#xff0c;一直是一个具有挑战性的问题。近年来&#xff0c;随着人工智能技术的发展&…...

Telegram电报+86手机接收验证码及账号解封方法

Telegram电报86手机无法接受验证码目前可用Telegram X获取&#xff0c;测试可用。获取验证码的前提是需要确保网络通畅 不要同一时段获取超过太多验证码&#xff0c;获取过多验证码将会很长一段时间收不到验证码&#xff0c;6小时最多获取2次验证码。 方法1&#xff1a;使用官…...

迅饶科技 X2Modbus 网关 AddUser 任意用户添加漏洞复现

0x01 产品简介 X2Modbus是上海迅饶自动化科技有限公司Q开发的一款功能很强大的协议转换网关, 这里的X代表各家不同的通信协议, 2是T0的谐音表示转换, Modbus就是最终支持的标准协议是Modbus协议。用户可以根据现场设备的通信协议进行配置,转成标准的Modbus协议。在PC端仿真…...

基于YOLOv8+PyQt5复杂场景下船舶目标检测系统

1. 应用场景 复杂场景下船舶目标检测系统的应用场景包括&#xff1a; 港口管理和安全&#xff1a;监控港口区域&#xff0c;确保船舶安全地进出港口&#xff0c;预防相撞事故的发生。 海洋交通监控&#xff1a;实时追踪海上交通流&#xff0c;并识别违规或异常航行行为&#x…...

做私服网站要多大空间/seo一个月赚多少钱

2020年&#xff0c;随着社会各个圈层对医美需求的高速增长&#xff0c;医美的“出圈”已经成为一个舆论普遍关注的现象。 一、2020&#xff0c;医美出圈 当前医美的“出圈”&#xff0c;已经被各个年龄层次、各种职业领域的女性&#xff0c;甚至男性人群普遍而强烈地感受到。…...

wordpress文章行间距/自动友链网

一、什么是设计模式&#xff1f; 设计模式&#xff0c;是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。 使用设计模式的目的&#xff1a;为了代码可重用性、让代码更容易…...

wx5 做网站可以么/百度一下官网首页百度

推进项目的能力&#xff0c;高级运维及架构师必备的能力...

wordpress如何实现登录注册功能/微信推广加人

一、首先回顾下什么是虚函数及其作用&#xff0c;以便更好理解什么函数不能声明或定义为虚函数&#xff1a; 1. 定义&#xff1a; 虚函数必须是基类的非静态成员函数&#xff0c;其访问权限可以是protected或public&#xff0c;在基类的类定义中定义虚函数的一般形式&#xf…...

网站设计与制/网上seo研究

Django官网地址&#xff1a;https://www.djangoproject.com/download/在django的官网上提供了两种安装方式&#xff1a; 1.通过pip命令进行安装&#xff1a;打开cmd命令行进行安装操作&#xff1a; 输入pip install Django2.0 在这里我安装的是django目前最新的2.0版本 如图所…...

企业级网站开发项目教程/seo千享科技

1.在VMware11中安装RHEL7.1&#xff0c;注意安装类型中选择带GUI的系统&#xff0c;电脑bios中一定开启虚拟化&#xff0c;VMware的cup一定要开启虚拟化&#xff0c;光驱一定选择自动连接和已连接&#xff0c;因为yum源中会用&#xff0c;如下图所示&#xff1a;2.进入系统后&a…...