手写实现深拷贝函数

对象相互赋值的一些关系,分别包括:

  • 引入的赋值:指向同一个对象,相互之间会影响;
  • 对象的浅拷贝:只是浅层的拷贝,内部引入对象时,依然会相互影响;
  • 对象的深拷贝:两个对象不再有任何关系,不会相互影响;

可以通过JSON.parse来实现深拷贝,但存在以下弊端:

  • 这种深拷贝的方式其实对于函数、Symbol等是无法处理的;
  • 并且如果存在对象的循环引用,也会报错的;
    在这里插入图片描述

在这里插入图片描述

一、简单的深拷贝函数实现

自定义深拷贝的基本功能:
在这里插入图片描述
在这里插入图片描述

二、对其他数据类型的值进行处理

包括:数组、函数、Symbol、Set、Map
在这里插入图片描述

在这里插入图片描述

function isObject(value) {const valueType = typeof valuereturn (value !== null) && (valueType === "object" || valueType === "function")
}function deepClone(originValue) {// 判断是否是一个Set类型if (originValue instanceof Set) {return new Set([...originValue])}// 判断是否是一个Map类型if (originValue instanceof Map) {return new Map([...originValue])}// 判断如果是Symbol的value, 那么创建一个新的Symbolif (typeof originValue === "symbol") {return Symbol(originValue.description)}// 判断如果是函数类型, 那么直接使用同一个函数if (typeof originValue === "function") {return originValue}// 判断传入的originValue是否是一个对象类型if (!isObject(originValue)) {return originValue}// 判断传入的对象是数组, 还是对象const newObject = Array.isArray(originValue) ? []: {}for (const key in originValue) {newObject[key] = deepClone(originValue[key])}// 上面的for循环是遍历不到key为Symbol的// 需要对key为Symbol的清空进行特殊处理const symbolKeys = Object.getOwnPropertySymbols(originValue)for (const sKey of symbolKeys) {// const newSKey = Symbol(sKey.description)newObject[sKey] = deepClone(originValue[sKey])}return newObject
}// 测试代码
let s1 = Symbol("aaa")
let s2 = Symbol("bbb")const obj = {name: "why",age: 18,friend: {name: "james",address: {city: "广州"}},// 数组类型hobbies: ["abc", "cba", "nba"],// 函数类型foo: function(m, n) {console.log("foo function")console.log("100代码逻辑")return 123},// Symbol作为key和value[s1]: "abc",s2: s2,// Set/Mapset: new Set(["aaa", "bbb", "ccc"]),map: new Map([["aaa", "abc"], ["bbb", "cba"]])
}const newObj = deepClone(obj)
console.log(newObj === obj) // falseobj.friend.name = "kobe"
obj.friend.address.city = "成都"
console.log(newObj)
console.log(newObj.s2 === obj.s2) // false

三、对循环引用进行处理

在这里插入图片描述

function isObject(value) {const valueType = typeof valuereturn (value !== null) && (valueType === "object" || valueType === "function")
}function deepClone(originValue, map = new WeakMap()) {// 判断是否是一个Set类型if (originValue instanceof Set) {return new Set([...originValue])}// 判断是否是一个Map类型if (originValue instanceof Map) {return new Map([...originValue])}// 判断如果是Symbol的value, 那么创建一个新的Symbolif (typeof originValue === "symbol") {return Symbol(originValue.description)}// 判断如果是函数类型, 那么直接使用同一个函数if (typeof originValue === "function") {return originValue}// 判断传入的originValue是否是一个对象类型if (!isObject(originValue)) {return originValue}// 判断当前传进来的对象是否已经在map中存在,如果是的话,// 直接返回key为这个对象的value,也就是我们所创建出来的newObject对象if (map.has(originValue)) {return map.get(originValue)}// 判断传入的对象是数组, 还是对象const newObject = Array.isArray(originValue) ? []: {}// 在第一次创建好newObject对象后,将其存去map中,key为需要进行深拷贝的对象,值为新创建好newObject对象map.set(originValue, newObject)for (const key in originValue) {newObject[key] = deepClone(originValue[key], map) // 把map作为函数的第二个参数传入}// 对Symbol的key进行特殊的处理const symbolKeys = Object.getOwnPropertySymbols(originValue)for (const sKey of symbolKeys) {// const newSKey = Symbol(sKey.description)newObject[sKey] = deepClone(originValue[sKey], map) // 把map作为函数的第二个参数传入}return newObject
}// deepClone({name: "why"})// 测试代码
let s1 = Symbol("aaa")
let s2 = Symbol("bbb")const obj = {name: "why",age: 18,friend: {name: "james",address: {city: "广州"}},// 数组类型hobbies: ["abc", "cba", "nba"],// 函数类型foo: function(m, n) {console.log("foo function")console.log("100代码逻辑")return 123},// Symbol作为key和value[s1]: "abc",s2: s2,// Set/Mapset: new Set(["aaa", "bbb", "ccc"]),map: new Map([["aaa", "abc"], ["bbb", "cba"]])
}obj.info = objconst newObj = deepClone(obj)
console.log(newObj === obj)obj.friend.name = "kobe"
obj.friend.address.city = "成都"
console.log(newObj)
console.log(newObj.s2 === obj.s2)console.log(newObj.info.info.info)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/470116.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一款支持容器和云部署的开源数据库Neo4j 3.0

导读Neo4j 3.0.0 正式发布,这是 Neo4j 3.0 系列的第一个版本。此版本对内部架构进行了全新的设计;提供给开发者更强大的生产力;提供更广阔的部署选择。Neo4j 3.0 被认为是世界上最具伸缩性的基于Java的图片数据库。Neo4j 3.0.0 主要的新特性&…

手写防抖和节流函数

一、认识防抖debounce函数 我们用一副图来理解一下它的过程: 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间;当事件密集触发时,函数的触发会被频繁的推迟;只有等待了一段时间也没有事件触…

中webgl解析json_WebGL蒙皮(下)

今天继续学习webgl一个重要功能:skinning(蒙皮),内容来自学习网站webglfundamentals,这里仅供学习交流,原文链接:https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-skinning.html。文章并非原创!如…

Vue权限控制——动态注册路由

需求:实现后台管理系统不同用户的权限控制 根据登录的用户的角色动态展示后台管理系统的左侧菜单栏的菜单列表内容,然后还要动态注册对应子菜单的路由 菜单列表内容应该通过后端接口返回: sort为1表示当前项有子菜单sort为2表示当前项没有子…

react不同环境不同配置angular_前端问题集:vue配置环境-给不同的环境配不同的打包命令...

通过vue-cli脚手架构建出一个前端项目,通过npm run build打包,发布到线上,但是这样做需要每次都手动修改接口地址。我们可以通过自行配置打包命令实现无需修改接口地址,打各个环境的包。文档结构大致如下图:1.找到conf…

基于Element-plus封装配置化表单组件(组件的v-model实现)

一、预备知识 1.1 组件的v-model 前面我们在input中可以使用v-model来完成双向绑定: 这个时候往往会非常方便,因为v-model默认帮助我们完成了两件事;v-bind:value的数据绑定 和 input的事件监听; 如果我们现在封装了一个组件…

Scala IDE for Eclipse的下载、安装和WordCount的初步使用(本地模式和集群模式)

不多说,直接上干货! 这篇博客是, 是在Scala IDEA for Eclipse里maven创建scala和java代码编写环境。 Scala IDEA for Eclipse里用maven来创建scala和java项目代码环境(图文详解) 本博文包括: Scala IDE fo…

笔记本AutoCAD启动时闪退怎么办_戴尔笔记本电脑开不了机如何解决【解决方法】...

生活在互联时代下,我们对笔记本的需求是无处不在的,不管是上班族还是学生党,使用笔记本办公和学习给我们的生活带来很大的便捷。但使用的过程中,总有可能会遇到无法预料的问题。比方说 笔记本电脑 无法开机的问题,当…

JS高级——函数执行、作用域链内存结构图

一、JavaScript的执行过程 假如我们有下面一段代码,它在JavaScript中是如何被执行的呢? 1.1 第一步:初始化全局对象 js引擎会在执行代码之前,会在堆内存中创建一个全局对象:Global Object(GO&#xff09…

JS高级——内存管理和闭包

0、预备知识 0.1 认识内存管理 不管什么样的编程语言,在代码的执行过程中都是需要给它分配内存的,不同的是某些编程语言需要我们自己手动的管理内存,某些编程语言会可以自动帮助我们管理内存: 不管以什么样的方式来管理内存&…

提取多个字段_【博客翻译】建筑物轮廓线提取以及损坏分类

原文链接原作者:Rohit Singh, Sandeep Kumar贡献者:Vinay Viswambharan, Divyansh Jha, Shivani Pathak, Daniel Wilson.翻译:荆雪涵在今年的 Esri 用户大会上,USAA 展示了基于 ArcGIS 深度学习能力,对 Woolsey 火灾进…

读取外部配置文件_SpringBoot外部配置、优先级及配置详解

一、外部配置及优先级SpringBoot的外部配置属性值官方给出了很多种方式,以便可以在不同的环境中使用相同的代码。其使用了非常特别的PropertySource命令,旨在允许合理的覆盖值。当然,如果属性值不同,则这些配置方式中的属性值都会…

Jquery 禁用浏览器的 后退和前进按钮

使用js,Jquery 禁用浏览器的back 和 next 按钮: 有时为了防治用户乱了访问顺序,不得不禁掉浏览器的前进后退按钮。 jQuery(document).ready(function () {if (window.history && window.history.pushState) {$(window).on(popstate, function ()…

JS数据结构与算法——冒泡排序(把大的数字依次往后放)

一、图解排序过程 注意:比较次数和交换次数之所以不一致,是因为:比较了并不一定就需要交换两个数字的位置,比如比较 1 和 2两个数字,由于 后者本身就比前者大,所以不需要交换两者的位置。 二、代码实现 三…

手机长曝光怎么设置_摄影教程丨手机如何拍摄长曝光照片,流光快门,星空银河搞起来!...

微信搜一搜定格取景框长曝光摄影可以拍摄出一些很酷的照片。这是一种非常灵活的摄影技术。它可以用来拍摄城市夜景,记录光绘,也可以拍摄水景片。甚至可以拍摄银河或捕捉星轨。其实长曝光不仅仅适合专业摄影师!任何人都可以用手机进行慢门拍摄…

JS数据结构与算法——选择排序(把小的数字依次往前放)

一、图解排序过程 注意&#xff1a;选择排序一样是需要进行两两的比较&#xff0c;但比较过程中不进行交换&#xff0c;只有比较完成后&#xff0c;找到最小的那个数&#xff0c;才会进行交换&#xff0c;把它放到最前面。 二、代码实现 三、完整代码 <!DOCTYPE html> &…

插入模板_WordPress在文章列表和内容页插入广告

本文已同步到专业技术网站 www.sufaith.com, 该网站专注于前后端开发技术与经验分享, 包含Web开发、Nodejs、Python、Linux、IT资讯等板块.一、在文章列表插入广告文章列表模板 包括以下几个类型以及对应的主体文件:首页模板 (index.php)搜索结果页 (search.php)文章归档 (arch…

JS数据结构与算法——插入排序

一、图解排序过程 二、代码实现 三、完整代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><script>// 创建列表类function ArrayList() {//…

cad完全卸载教程_CAD室内设计中厨房布置实例

▲ 点击“CAD教学”&#xff0c;获取海量学习资料和免费教程本文介绍CAD室内设计中厨房布置方法&#xff1a;1、如下图是把另一边墙砌好&#xff0c;因为不砌的话门太大的话不好。在煮菜的烟容易在烟到不胜客厅里。2、在用矩形画宽为40长为800的玻璃门。3、在把厨房的台画出来&…

CSS布局(圣杯布局、双飞翼布局、水平垂直居中)

一、圣杯布局 要求&#xff1a;三列布局&#xff1b;中间主体内容前置&#xff0c;且宽度自适应&#xff1b;两边内容定宽 好处&#xff1a;重要的内容放在文档流前面可以优先渲染 原理&#xff1a;利用相对定位、浮动、负边距布局&#xff0c;而不添加额外标签 <!DOCTYPE …