如果说道实现深拷贝最简单的方法,我们第一个想到的就是 JSON.stringify() 方法,因为JSON.stringify()后返回的是字符串,所以我们会再使用JSON.parse()转换为对象,如下代码:

let obj = { name: 'liaoyi',age: 22,sex: 1}
JSON.parse(JSON.stringify(obj))

但是这种克隆不够完美,有一个致命的问题无法解决,就是她一旦遇到循环引用就会报错:

let obj = { name: 'liaoyi',age: 22,sex: 1}
JSON.parse(JSON.stringify(obj))
obj.c = obj
console.log(JSON.stringify(obj))

js会报错,无法把一个循环引用转成 json 格式:

在这种情况下,我们通常想到的是写一个正儿八经的深度克隆方法:

使用传统方式实现对象的深拷贝

function deepClone(obj) {
const objectMap = new Map();
const _deepClone = value => {
const type = typeof value;
if (type !== 'object' || type === null) {
return value;
}
if (objectMap.has(value)) {
return objectMap.get(value);
}
const result = Array.isArray(value) ? [] : {}; objectMap.set(value, result); for (const [key, _v] of Object.entries(value)) {
result[key] = _deepClone(value[key]);
console.log(key, _v);
}
return result;
};
return _deepClone(obj);
}

使用 MessageChannel 实现循环引用对象的深拷贝

不够新鲜,我们来看一个好玩的 Web API

参考链接: MessageChannel

MessageChannel允许我们在不同的浏览上下文,比如window.open()打开的窗口或者iframe等之间建立通信管道,并通过两端的端口(port1和port2)发送消息。MessageChannel以DOM Event的形式发送消息,所以它属于异步的宏任务。

// 通过这个构造函数,创建一个消息通道,它会返回一个对象,解构 port1, port2 来实现通信
const { port1, port2 } = new MessageChannel();
port1.postMessage('hello')
port2.onmessage = msg => {
console.log(msg.data) // hello
}

我们可以利用这个API,实现循环引用对象的深拷贝:

 function deepClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel();
port1.postMessage(obj); port2.onmessage = msg => {
resolve(msg.data);
// console.log(obj, msg.data === obj); // false
};
})
} const obj = { a: 1, b: '2' }
obj.c = obj;
deepClone(obj).then(res =>{
console.log('res',res);
})

JavaScript 深拷贝的循环引用问题的更多相关文章

  1. javascript中的循环引用对象处理

    先说明一下什么是循环引用对象: var a={"name":"zzz"}; var b={"name":"vvv"}; ...

  2. [ Javascript ] 内存泄露以及循环引用解析

    内存泄露 在javascript中,我们非常少去关注内存的管理. 我们创建变量,使用变量,浏览器关注这些底层的细节都显得非常正常. 可是当应用程序变得越来越复杂而且ajax化之后,或者用户在一个页面停 ...

  3. WeakMap与Map,使用WeakMap实现深拷贝循环引用问题

    1.Map可以使用任意类型的key值,不限字符串,对象等. 2.WeakMap只能使用对象作为key值,是弱引用,当从WeakMap中移除时,会自动垃圾回收 3.Object只能用基本类型作为key值 ...

  4. 读懂javascript深拷贝与浅拷贝

    1. 认识深拷贝和浅拷贝 javascript中一般有按值传递和按引用传递两种复制,按值传递的是基本数据类型(Number,String,Boolean,Null,Undefined),一般存放于内存 ...

  5. JavaScript 深拷贝(deep copy)和浅拷贝(shallow copy)

    参考: [进阶4-1期]详细解析赋值.浅拷贝和深拷贝的区别 How to differentiate between deep and shallow copies in JavaScript 在编程 ...

  6. 这一次,彻底理解JavaScript深拷贝

    导语 这一次,通过本文彻底理解JavaScript深拷贝! 阅读本文前可以先思考三个问题: JS世界里,数据是如何存储的? 深拷贝和浅拷贝的区别是什么? 如何写出一个真正合格的深拷贝? 本文会一步步解 ...

  7. javascript 深拷贝与浅拷贝

    javascript 深拷贝与浅拷贝 深拷贝与浅拷贝 赋值和深/浅拷贝的区别 浅拷贝的实现方式 1.Object.assign() 2.函数库lodash的_.clone方法 3.展开运算符... 4 ...

  8. iOS Block循环引用

    在介绍block循环引用前我们先了解一下typeof. typeof是什么??? typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型. 它返回值是一个字符串,该字符串说明运算数的类 ...

  9. IOS block 循环引用的解决

    在介绍block循环引用前我们先了解一下typeof. typeof是什么??? typeof 是一个一元运算,放在一个运算数之前,运算数可以是任意类型. 它返回值是一个字符串,该字符串说明运算数的类 ...

  10. 用JSON.stringify处理循环引用对象

    通常,我们会用JSON.stringify把Javascript对象序列化成JSON格式,这在大多数情况下是够用的.但是,当你要转换的对象里存在循环引用时,问题就来了. js对象循环引用导致内存泄漏 ...

随机推荐

  1. 矩阵顺时针打印(C++)(? 为什么不能AC,9度1391)

    #include <iostream> #include <fstream> using namespace std; int a[1000][1000]; void prin ...

  2. count(*), count(1), count(列名)的区别

    1.从结果上来看 count(1)和count(*)之间没有区别,因为count(*)count(1)都不会去过滤空值,但count(列名)就有区别了,因为count(列名)会去过滤空值. 2.从执行 ...

  3. Struts中action访问不到的原因。

    因为需要在项目中构造restful的链接,action通配符使用/进行分割.但是struts默认不支持反斜杠. 所以需要在Struts.xml配置 <constant name="st ...

  4. Windows应急响应——敬请期待!

    检查内容 进程.服务.用户.网络连接.漏洞补丁.木马查杀. 工具 火绒剑. 防护措施 杀毒软件

  5. 实验6:开源控制器实———RYU

    一.实验目的 1.能够独立部署RYU控制器: 2.能够理解RYU控制器实现软件定义的集线器原理: 3.能够理解RYU控制器实现软件定义的交换机原理. 二.实验环境 Ubuntu 20.04 Deskt ...

  6. 笔记:Debian下为sublime text建立软链接[像vi一样到处使用]

    先查询sublime-text安装路径 :~$ dpkg -L sublime-text /. /opt /opt/sublime_text ... /opt/sublime_text/sublime ...

  7. Android开发 对接微信分享SDK总结

    原文:Android开发 对接微信分享SDK总结 - Stars-One的杂货小窝 公司项目需要对接微信分享,本来之前准备对接友盟分享的,但友盟的分享实际参数太多,而我又只需要对接一个微信分享,于是便 ...

  8. vim-瞬间移动打发

    一,常用基本命令 set rnu 显示相对行号 1.ctrl+F 将屏幕向下滚动一屏 2.ctrl+u pageUp,ctrl+d pageDown 3.行内移动:W,b在单词间移动,ge向上跳,f ...

  9. Phalcon notes

    1. 半原生数据查询: echo $realUser->getReadConnection()->getSQLStatement();die;

  10. 一个jsqlparse+git做的小工具帮我节省时间摸鱼

    背景 前些时间做了个小工具解决了团队内数据库脚本检验&多测试环境自动执行的问题,感觉挺有意思,在这跟大家分享一下. 工具诞生之前的流程是这样: 1.开发人员先在开发环境编写脚本&执行: ...