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

news/2024/11/20 0:24:14/

浅拷贝

浅拷贝 : 浅拷贝是指对基本类型的值拷贝,以及对对象类型的地址拷贝。它是将数据中所有的数据引用下来,依旧指向同一个存放地址,拷贝之后的数据修改之后,也会影响到原数据的中的对象数据。最简单直接的浅拷贝就是直接赋值,如: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个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



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


http://www.ppmy.cn/news/24202.html

相关文章

C语言---字符串函数总结

🚀write in front🚀 📝个人主页:认真写博客的夏目浅石. 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝 📣系列专栏:夏目的C语言宝藏 💬总结:希望你看完之…

分布式架构下,Session共享有什么方案?

分布式架构下,Session共享有什么方案? 1.不要有Session:但是确实在某些场景下,是可以没有session的,其实在很多借口类系统当中,都提倡【API无状态服务】; 也就是每一次的接口访问,都…

Python+Go实践(电商架构三)

文章目录服务发现集成consul负载均衡负载均衡算法实现配置中心nacos服务发现 我们之前的架构是通过ipport来调用的python的API,这样做的弊端是 如果新加一个服务,就要到某个服务改web(go)层的调用代码,配置IP/Port并发…

结构体变量

C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,它称为结构体(structre)。 在程序中建立一个结构体类型: 1.结构体 建立结构体 struct Student { int num; //学号为整型 char name[20]; //姓名为字符串 char se…

English Learning - Day5 L1考前复习 2023.2.10 周五

English Learning - Day5 L1考前复习 2023.2.10 周五1 单选题:She has the face _________.2 单选题: The goals ________ he fought all his life no longer seemed important to him.3 单选题:Sales director is a position ______ communi…

有趣的Hack-A-Sat黑掉卫星挑战赛——定位卫星Jackson

国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加,太空已经成为国家赖以生存与发展的命脉之一,凝聚着巨大的国家利益,太空安全的重要性日益凸显[1]。而在信息化时代,太空安…

电子电路中的各种接地(接地保护与GND)

前言多年以前,雷雨天气下,建筑会遭遇雷击,从而破坏建筑以及伤害建筑内的人,为了避免雷击的伤害,人们发明了避雷针,并将避雷针接地线,从而引导雷击产生的电流经过地线流入到地下。地线&#xff1…

事务基础知识与执行计划

事务基础知识 数据库事务的概念 数据库事务是什么? 事务是一组原子性的SQL操作。事务由事务开始与事务结束之间执行的全部数据库操作组成。A(原子性)、(C一致性)、I(隔离性)、D(持久…