当前位置: 首页 > 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;导致无…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...