前言:
2020年,对所有人来说都是一个不平凡的一年.疫情,很沉重的一个词.到目前为止,很多省都保持0新增
.愿祖国一直健康下去...
4月份中旬,终于下定决心,五月份离职.辞职申请流程已经提交,本以为,带过项目,
负责公司前端大大小小的项目搭建,代码开发,公共组件构建,各种框架信手拈来,
一个面试而已,小case,应该没啥问题.
然而在前两天面试时的经历,却是迎头一棒,让我瞬间清醒,终究还是捡了芝麻,丢了西瓜.
很简单的几个问题,其中就有这篇文章准备讲的深拷贝与浅拷贝.而我没答上来,甚至很多基础都没答上来.
其实一切的框架都是浮云.对于前端来说,JavaScript才是根本.
重新回顾各种JavaScript基础.
如何区分深拷贝与浅拷贝?
1、什么是深拷贝?什么是浅拷贝?
浅拷贝: 它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类
型,拷贝的就是基本类型的值;
如果属性是内存地址(引用类型),拷贝的就是内存地址。即只复制对象空间而不复制资源
深拷贝: 它会创建一个新对象,给这个新对象新开一个内存地址,源对象与拷贝对象互相独立,
其中任何一个对象的改动都不会对另外一个对象造成影响
(上述解释来自百度百科)
看不懂?看不懂没关系,我们换一种方式来说。
浅拷贝可以理解为浅复制。同理,深拷贝可以理解为深复制
浅拷贝(浅复制):浅拷贝仅仅是复制一份复制体,但是指针(JS没指针,但是可以去这样理解)
还是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象
也会相应改变.
浅拷贝实际上只复制一层对象,当对象的属性是引用类型时,实际复制的是其引用,
当引用指向的值改变时也会跟着变化
深拷贝(深复制):深拷贝是复制一份复制体,在内存栈中新开一份地址,把复制体放进去。
所以,复制体和被复制体之间完全独立,没有任何影响。可以复制对象的所有层级.
举个例子,一个魔方放在桌子上,小明手里没有魔方,小明说:我有,
我的魔方就是桌子上那个。小军去拿了一个魔方,调成和桌子上的魔方一样。
小明有没有魔方?有,桌子上那个(指向桌子)。小军也有,自己有一个,
如果我们把桌子上的魔方打乱顺序,小明的魔方顺序也跟着变了(浅拷贝),
但是小军的没变(深拷贝)。
如果我们把桌子上的魔方拿走了,小明的魔方就没了(空指针)。小军的还在(新
开内存地址)
所以,当我们区别深拷贝与浅拷贝时.如果被复制体改变了,复制体也跟着改变.或者只复制了一层对象,那么,
我们就视作浅拷贝.
如果复制了多层对象并且复制体不会跟随被复制体改变,那么,就可以视为深拷贝.
这个意思我们知道了,那么,作为程序员,还是上代码吧。眼见为实。
实现浅拷贝的方法:
方法一 直接赋值

当obj1修改时,obj2也跟着修改了
现在我们有这么一个需求,我们有了一个对象A,但是我想再有一个对象B,和对象A相互独立.此时,我们怎么做呢?
方法二for in ,forEach)

这里就完成了一个相互独立的浅拷贝.注意:这还是浅拷贝.为什么,只复制了一层对象. 上面的代码,我解释一下, 当我们循环赋值时,为什么用了forEach而不是直接for in 或者 for of 如果熟悉ESlint的话,那么会知道,此处用for in 是会报错的. 大概意思就是使用for..in会遍历整个原型链,这样不是很好的实现方法,推荐使用Object.keys. 什么是原型链,后续我们会继续写到.
方法三:ES6的Object.assign()方法

实际上,Object.assign()也是一个浅拷贝.
实现深拷贝的方法:
实现深拷贝,一般我们工作中常用的是JSON.stringify()方法;除此之外就是利用递归
方法一:JSON.parse(JSON.stringify())
就是利用 JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象
但是存在局限性,无法实现对对象中方法的深拷贝,会显示为undefined (这次面试就问到了这个,我没答对)
所以一般此方法常用于处理json和数组的深拷贝

方法二: 利用递归实现深拷贝

方法三: 不闲麻烦的可以手动深复制(不推荐,这里不做多说明)
方法四 lodash函数库的_.cloneDeep()方法
let newObj = _.cloneDeep(obj)
除此之外,还能进行深拷贝的有,Array的slice()方法,concat()方法 Object的create()方法
示例:
const arr = [1,2,3]
const arr1 = [4,5,6]
const arr2 = arr.slice(0)
arr2[0] = 999 ,
有兴趣可以去打印一下arr 和 arr2的值
这里说明一下, 当数组里面的值是基本数据类型,比如String,Number,Boolean时,属于深拷贝
当数组里面的值是引用数据类型,属于浅拷贝
const arr3 = arr1.concat()
arr3[0] = 999
还有一个ES6的扩展运算符,[...arr], 扩展运算符和slice一样,当数组里面的值是基本数据类型,
比如String,Number,Boolean时,属于深拷贝,当数组里面的值是引用数据类型,属于浅拷贝
有些内容来自与百度,如有侵权,请联系删除.
学艺未精,往诸位看官指正.
不求与人相比,但求超越自己,要哭就哭出激动的泪水,要笑就笑出成长的性格!