前端对于深拷贝和浅拷贝的应用和思考
浅拷贝
浅拷贝 : 浅拷贝是指对基本类型的值拷贝,以及对对象类型的地址拷贝。它是将数据中所有的数据引用下来,依旧指向同一个存放地址,拷贝之后的数据修改之后,也会影响到原数据的中的对象数据。最简单直接的浅拷贝就是直接赋值,如: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,γ>,其中: S\mathcal{S}S:状态空间A\mathcal{A}A:动作空间P\mathc…...
刘润:五维思考,让你站得更高、看得更远
原标题:刘润:五维思考,让你站得更高、看得更远 前言:遇到问题时,有的人很快就能想明白,有的人需要很久才能想明白,还有的人始终都想不明白。 而且,那些很快就能想明白的人࿰…...
从运维角度看微服务 k8s部署微服务【偏理论】【AL】
从运维角度看微服务 & 部署微服务【偏理论】 1、微服务的特点 服务组件化: 每个服务独立开发、部署,有效避免一个服务的修改引起整个系统重新部署。 技术栈灵活: 约定通信方式,使得服务本身功能实现对技术要求不再那么敏感。…...
专题 | 防抖和节流
一 防抖:单位时间内,频繁触发事件,只执行最后一次 场景:搜索框搜索输入(利用定时器,每次触发先清掉以前的定时器,从新开始) 节流:单位时间内,频繁触发事件&…...
C++入门:重载运算符和重载函数
C 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。当您调用一个重载函…...
conda 新建虚拟环境 等等
1:conda create -n env_name package_name #创建名为env_name的新环境,并在该环境下安装名为package_name 的包,例如:conda create -n Arg python3.8 # 创建名字为Arg python为3.8版本的虚拟环境2: 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项目)
【辰兮要努力】:hello你好我是辰兮,很高兴你能来阅读,昵称是希望自己能不断精进,向着优秀程序员前行! 博客来源于项目以及编程中遇到的问题总结,偶尔会有读书分享,我会陆续更新Java前端、后台、…...
华为OD机试 - 计算网络信号(Python),真题含思路
计算网络信号 题目 网络信号经过传递会逐层衰减,且遇到阻隔物无法直接穿透,在此情况下需要计算某个位置的网络信号值。 注意:网络信号可以绕过阻隔物 array[m][n] 的二维数组代表网格地图,array[i][j] = 0 代表 i 行 j 列是空旷位置;array[i][j] = x ( x 为正整数)代表 i …...
【Spring】注解实现IOC操作,你理解了吗?
作者:狮子也疯狂 专栏:《spring开发》 坚持做好每一步,幸运之神自然会驾凌在你的身上 专栏推荐:写文章刚刚起步,各个专栏的知识点后续会补充完善,不断更新好文,希望大 家支持一下。 专栏名字El…...
微搭低代码从入门到精通01-总体介绍
在过去我们开发小程序,要学习各类知识。比如前端知识、后端知识、服务器知识及各种中间件及数据库的知识。 要想学会这些知识,既需要投入大量的学习时间,而且要经过相当的实践才可以掌握。 如果立志从事开发行业,投入精力去学习…...
类的继承
类的继承:一个类继承另一个类,自动拥有这个类的属性和方法,类似于包含与被包含的关系。被继承的类称为父类--子类则是继承父类的类。一个父类可以有多个子类;一个子类可以有多个父类(多继承)问题创建子类时…...
应用场景一:西门子PLC通过桥接器连接MQTT服务器
应用场景描述: 云平台、MES等数据采集、设备管理系统,需要通过MQTT的方式,上传和下发数据,MQTT服务器可以获取PLC的实时状态数据,也可以下发控制指令。桥接器提供4G、WIFI和有线三种连接方式。 网络拓扑:…...
计算机组成原理(四)
1.理解存储器的分类方法;理解存储器的层次结构;熟悉存储器的几个技术指标(主要是存储容量、存取时间、存取周期、存储器带宽等); 存储器分类方法: 按与CPU的连接和功能分类: 主存储…...
状态机设计举例
⭐本专栏针对FPGA进行入门学习,从数电中常见的逻辑代数讲起,结合Verilog HDL语言学习与仿真,主要对组合逻辑电路与时序逻辑电路进行分析与设计,对状态机FSM进行剖析与建模。 🔥文章和代码已归档至【Github仓库…...
Kubernetes1.25中Redis单机和集群部署实例二
1、概述我们知道在 Kubernetes 容器编排平台中, 我们可以非常方便的进行应用的扩容缩, 同时也能非常方便的进行业务的迭代,本章主要讲解在Kubernetes1.25搭建Redis单实例和Redis集群主从同步的环境流程步骤, 如果是高频访问重要的线上业务我们最好是部署在物理机器上…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...
CppCon 2015 学习:REFLECTION TECHNIQUES IN C++
关于 Reflection(反射) 这个概念,总结一下: Reflection(反射)是什么? 反射是对类型的自我检查能力(Introspection) 可以查看类的成员变量、成员函数等信息。反射允许枚…...
