你还在用乞丐版的深拷贝么

乞丐版:JSON.parse(JSON.stringify());

这种写法非常简单,而且可以应对大部分的应用场景,但是它还是有很大缺陷的,比如拷贝其他引用类型、拷贝函数、循环引用等情况。

基础版本

如果是浅拷贝的话,下面的很容易:

function clone(target){let cloneTarget = {};for (const key in target) {cloneTarget[key] = target[key];}return cloneTarget;
}

创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性依次添加到新对象上,返回。

如果是深拷贝的话,考虑到我们要拷贝的对象是不知道有多少层深度的,我们可以用递归来解决问题,稍微改写上面的代码:

  • 如果是原始类型,无需继续拷贝,直接返回
  • 如果是引用类型,创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性执行深拷贝后依次添加到新对象上。

很容易理解,如果有更深层次的对象可以继续递归直到属性为原始类型,这样我们就完成了一个最简单的深拷贝:

function clone (target) {if (typeof target === 'object') {let cloneTarget = {};for (const key in target) {cloneTarget[key] = clone(target[key])}return cloneTarget;} else {return target;}
}

这是一个最基础版本的深拷贝,这段代码可以让你向面试官展示你可以用递归解决问题,但是显然,他还有非常多的缺陷,比如,还没有考虑数组。

考虑数组

在上面的版本中,我们的初始化结果只考虑了普通的object,下面我们只需要把初始化代码稍微一变,就可以兼容数组了:

function clone(target) {if (typeof target === 'object') {let cloneTarget = Array.isArray(target) ? [] : {};for (const key in target) {cloneTarget[key] = clone(target[key]);}return cloneTarget;} else {return target;}
};

循环引用

const target = {field1: 1,field2: undefined,field3: {child: 'child'},field4: [2, 4, 8]
};
target.target = target;

解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系,当需要拷贝当前对象时,先去存储空间中找,有没有拷贝过这个对象,如果有的话直接返回,如果没有的话继续拷贝,这样就巧妙化解的循环引用的问题。

这个存储空间,需要可以存储key-value形式的数据,且key可以是一个引用类型,我们可以选择Map这种数据结构:

  • 检查map中有无克隆过的对象
  • 有 - 直接返回
  • 没有 - 将当前对象作为key,克隆对象作为value进行存储
  • 继续克隆
function clone(target, map = new Map()) {if (typeof target === 'object') {let cloneTarget = Array.isArray(target) ? [] : {};if (map.get(target)) {return map.get(target);}map.set(target, cloneTarget);for (const key in target) {cloneTarget[key] = clone(target[key], map);}return cloneTarget;} else {return target;}
};

接下来,我们可以使用,WeakMap提代Map来使代码达到画龙点睛的作用。

为什么要这样做呢?,先来看看WeakMap的作用:

WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。

什么是弱引用呢?

在计算机程序设计中,弱引用与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。 一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。

我们默认创建一个对象:const obj = {},就默认创建了一个强引用的对象,我们只有手动将obj = null,它才会被垃圾回收机制进行回收,如果是弱引用对象,垃圾回收机制会自动帮我们回收。

举个例子:

如果我们使用Map的话,那么对象间是存在强引用关系的:

let obj = { name : 'ConardLi'}
const target = new Map();
target.set(obj,'code秘密花园');
obj = null;

虽然我们手动将obj,进行释放,然是target依然对obj存在强引用关系,所以这部分内存依然无法被释放。

再来看WeakMap

let obj = { name : 'ConardLi'}
const target = new WeakMap();
target.set(obj,'code秘密花园');
obj = null;

如果是WeakMap的话,targetobj存在的就是弱引用关系,当下一次垃圾回收机制执行时,这块内存就会被释放掉。

设想一下,如果我们要拷贝的对象非常庞大时,使用Map会对内存造成非常大的额外消耗,而且我们需要手动清除Map的属性才能释放这块内存,而WeakMap会帮我们巧妙化解这个问题。

https://juejin.cn/post/6844903929705136141#heading-2

你还在用乞丐版的深拷贝么相关推荐

  1. python四则运算器tkinter_Python基于Tkinter的二输入规则器(乞丐版)

    Python 2.7 IDE Pycharm 5.0.3 有想法就去做,等等等等就没机会了 起因 昨天接触了Tkinter框架,之后就迫不及待的想写个计算器出来,结果呢,可想而知了,当初自己犟脾气,掌 ...

  2. 马斯克把飞船方向盘用在特斯拉新车上!乞丐版80万起

    贾浩楠 萧箫 发自 凹非寺 量子位 报道 | 公众号 QbitAI 马斯克随手升级旧车型,特斯拉立刻成车圈科技圈--甚至航天圈热议焦点. 这不,赛车式的方向盘(也有说宇宙飞船样式),现在成了升级后的新 ...

  3. android平板开箱,安卓平板不行了吗?小米平板4乞丐版开箱体验

    安卓平板不行了吗?小米平板4乞丐版开箱体验 2018-11-11 18:50:00 19点赞 12收藏 44评论 由于晚上开箱就顺手拍照了,光线实在不好,请大家见谅 购买理由 购买之路,就是一个不断减 ...

  4. C#实现乞丐版IOC容器

    一.前言 netcore中的容器非常好用,今天我们自己来简单实现一个. 实现容器的核心接口有两个:IServiceCollection.IServiceProvider.其中IServiceColle ...

  5. 来电通java版_还在玩JAVA版《我的世界》?教你怎么转换存档玩光追!

    简介 如果你一直在花时间扩展和开发"我的世界 (Minecraft)" Java 版世界,那下面为你公布一则好消息:此版本现可转换为"我的世界 (Minecraft)&q ...

  6. java代码实现在Windows中自动连接WiFi(乞丐版)

    之前在学校用校园网时每次开机自己都要连接WiFi然后手动登入校园账号,频繁的登入使我萌生了能不能用代码来完成这些操作.说动手就动手,但现在暑假不在学校无法查看校园登入的一些参数,于是打算先实现自动连接 ...

  7. 正版Xshell 7免费使用,你还在找破解版吗

    原文地址:正版Xshell/Xftp免费使用,你还在找破解版吗 想必很多人都和我一样使用一款软件,先是去官网下载.用了一段时间后提示要付费就直接搜破解版接着用. 今天阿福的Xshell就到期了,笔记本 ...

  8. mac linux 蓝牙键盘,还在纠结Mac版键盘?试试KeyRemap4MacBook吧!

    本帖最后由 亦草亦木 于 2013-2-18 02:03 编辑 有时候能在外设区看到坛子里的朋友发帖求适合Mac的键盘,其实键盘这个东西Mac上和PC上真的没有太大的区别,只不过是键盘映射不同,还有就 ...

  9. 又涨价了!华为 P40系列海外售价曝光:还好国行版友好不少

    随着昨日又两款5G旗舰--努比亚红魔5G游戏手机和realme X50 Pro与我们见面,今年的开年旗舰大战基本进入尾声,而要担当压轴重任的,自然是备受关注的华为P40系列新机. 根据华为官方官宣的消 ...

  10. 仿作小米官网-乞丐版

    这几天学习进度落了很多,导致做的时候很不流畅,很多都不会,都要用到后面的浮什么的,所以我用仅存的知识做了个丐版的 完整代码为 <!DOCTYPE html> <html lang=& ...

最新文章

  1. matlab数组操作
  2. linux mate桌面主题下载_7款Linux桌面环境推荐,你值得拥有!
  3. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)
  4. Vue使用Element-ui按需引入大坑
  5. [微积分] 常用定义与公式
  6. 解决Linux系统在设置alias命令重启后失效的问题
  7. Java 在方法和作用域内的内部类
  8. 矩阵的伴随矩阵的伴随矩阵
  9. 白化滤波器 matlab,白化滤波器-matlab-程序.doc
  10. 传统安防企业资本运作:找准定位、创新为本
  11. 1月1日服务器例行维护公告,1月1日服务器例行维护公告(已完成)
  12. dwf是什么格式文件
  13. Ubuntu下编译OpenHarmony
  14. 计算机打印机副机无法打印,打印机共享无法打印怎么办,教您解决电脑打印机共享无法打印...
  15. matlab分组形式条形图,Matplotlib带标签的分组条形图
  16. [数字图像处理]图像复原--逆滤波
  17. [ARM入门]消失的飞思卡尔:MKV30 16位AD采集
  18. 股票数据-股票免费查询AP
  19. 汇编语言寻址方式总结
  20. STC89C52RC的特殊功能寄存器

热门文章

  1. 三栏式布局详解(代码+图解)
  2. java char a z_java中,char A,char a的值各是多少?
  3. android背景置灰,android view置灰(哀悼日)
  4. 08-微信公众号素材管理
  5. 【人体骨骼点】算法综述
  6. 登陆apple pay显示无法登录服务器,apple pay无法添加卡怎么办?未能连接到apple pay的解决方法...
  7. boseqc35能不能连电脑_求教boseqc35如何连接win10电脑
  8. 手游传奇架设教程_传奇手游战神引擎架设教程
  9. java获取手机型号
  10. 【 直接复制不用下载 】-- 走遍美国总词汇(完整版)