【JavaScript】面试手撕深拷贝

【JavaScript】面试手撕深拷贝

    正在检查是否收录...



?个人主页: 鑫宝Code
?热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础
​?个人格言: "如无必要,勿增实体"

文章目录

引入 深拷贝的作用 深浅拷贝的区别 浅拷贝 深拷贝 深拷贝实现方式 JSON.parse(JSON.stringify()) 介绍 使用例子 缺点 Lodash的cloneDeep 介绍 使用例子 缺点 手撕深拷贝 基础版本 进阶版本 参考资料

引入

上次讲了浅拷贝,这次我们来讲深拷贝。有一说一,深拷贝也算是面试时非常常见的题目了。?

深拷贝的作用

首先为什么需要深拷贝,因为浅拷贝无法满足我们对原始数据完整、独立复制的需求。我们希望修改新对象不会影响原对象。

深浅拷贝的区别

这里引用ConardLi大佬的理解

浅拷贝

创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。

如果属性是基本类型,拷贝的就是基本类型的值. 如果属性是引用类型,拷贝的就是内存地址

所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝

将一个对象从内存中完整的拷贝一份出来

从堆内存中开辟一个新的区域存放新对象 且修改新对象不会影响原对象

深拷贝实现方式

JSON.parse(JSON.stringify())

遥记当年,我当时还是大三的时候,背了一周的面经就跑去字节面试实习生了。面试官就让我手撕深拷贝。

我当时才20刚出头,前端面经也才抱起来背了不到一周。这种题目我写的来得?

跟面试官面面相觑了半天,突然灵机一动,JSON.parse(JSON.stringfy())大法一定可以。

我当时非常开心的说出了这个答案, 面试官当时好像有点尬住了,嘴角流露出一股察摸不到的笑容。

但可能由于接受过专业的训练,也只在那短短的时间内便消失不见。?

介绍

JSON.parse(JSON.stringify()),首先使用利用JSON.stringify将对象转成JSON字符串。 再用JSON.parse把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

使用例子
const a = { name: '张三', score:{ math: 100 } } const b = JSON.parse(JSON.stringify(a)); // 改变b中的对象的值 b.score.math = 60; console.log('a的值',a); console.log('b的值',b); /*  输出的结果如下  a的值 { name: '张三', score: { math: 100 } }  b的值 { name: '张三', score: { math: 60 } } / 
缺点

记个TODO:下次写文章详细分析下JSON.stringify的缺点。

不会拷贝对象上为undefined的值 不能处理函数 不能处理正则 循环引用会报错 Symol会丢失等

Lodash的cloneDeep

续借上文,面试官笑了笑,说JSON.parse(JSON.stringify())这个方式有如上几个缺点,你能不能换个更好的方式将这个问题解决呢?

这又一次的让我陷入了思索,又开始了与面试官的面面相觑?。突然我想起了以前用的Lodash,其中有一个NB的方法。cloneDeep,当时我洋洋得意,心想lodash库的方法,总不可能还有缺点吧?

此时,面试官的表情稍稍有点微妙,我的第六感告诉我,我好像答错了,不过我认为我回答的没问题呀。

晌久,面试官叹了口气说,我是让你手撕,手撕懂吗?

介绍

_.cloneDeeplodash库提供的深拷贝的方法,非常实用,建议背诵?。

使用例子
import  as  from "lodash"; const a = { name: "张三", score: { math: 100, }, }; const b = .cloneDeep(a); 
缺点

暂无,?的lodash库,?的cloneDeep函数。

手撕深拷贝

诶,还是得手撕呀,来吧来吧,还是得给面试官露一手的?

基础版本

多年面试经验告诉我,一般写出这个版本,几乎都让过了,顶多在回答一下循环引用问题如何解决。一般不太会让写一个比较完美的深拷贝的。?

首先,我们要拷贝的数据类型有两种,分别是ArrayObject 如果对象里的属性还是对象,那么采用递归对这个对象再进行拷贝 如果对象里的属性不是对象,那么直接返回即可。

代码如下:

function deepClone(target) { if (typeof target === "object") { let cloneTarget = Array.isArray(target) ? [] : {}; for (const key in target) { cloneTarget[key] = deepClone(target[key]); } return cloneTarget; } else { return target; } } const a = { name: "张三", score: { math: 100, }, }; const b = deepClone(a); / 输出的b与a一样 / 

但是这样实现会有若干个问题:

循环引用问题无法解决 DateRegExp等对象无法拷贝

进阶版本

之所以用weakMap,是因为weakMap的键是弱引用,可以在任何时刻被回收。

如果想了解更清楚进阶深拷贝的原理,可以参阅 如何写出一个惊艳面试官的深拷贝?

function deepClone(target, hash = new WeakMap()) { if (target === null) return null; if (typeof target !== "object") return target; if (target instanceof Date) return new Date(target); if (target instanceof RegExp) return new RegExp(target); // 如果hash里有值,立马返回 if (hash.has(target)) return hash.get(target); const cloneTarget = Array.isArray(target) ? [] : {}; hash.set(target,cloneTarget); if (typeof target === "object") { for (const key in target) { cloneTarget[key] = deepClone(target[key],hash); } return cloneTarget; } else { return target; } } const a = { name: "张三", score: { math: 100, }, date: new Date(), regex: /^\d{3,4}-\d{5,8}$/, }; a.child = a; const b = deepClone(a); 

运行结果如下:

参考资料

如何写出一个惊艳面试官的深拷贝?

浅拷贝与深拷贝

clonejsongifparse参考资料todo写文章问题解决defijavascripthtmljavacodescript

  • 本文作者:李琛
  • 本文链接: https://wapzz.net/post-11766.html
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
本站部分内容来源于网络转载,仅供学习交流使用。如涉及版权问题,请及时联系我们,我们将第一时间处理。
文章很赞!支持一下吧 还没有人为TA充电
为TA充电
还没有人为TA充电
0
  • 支付宝打赏
    支付宝扫一扫
  • 微信打赏
    微信扫一扫
感谢支持
文章很赞!支持一下吧
关于作者
2.3W+
5
0
1
WAP站长官方

微软获得Inflection大模型使用权及大部分员工

上一篇

AI推理和训练有什么不同?你知道吗?

下一篇
  • 复制图片
按住ctrl可打开默认菜单