小tips:使用JSON.parse(JSON.stringify(object))实现深拷贝的局限及扩展
使用JSON.parse(JSON.stringify(object))实现深拷贝局限
大部分情况我们都可以使用JSON.parse(JSON.stringify(object))来实现深拷贝,但该方法也有局限性,如下:
- 会忽略
undefined
- 会忽略
symbol
- 不能序列化函数
- 不能解决循环引用的对象
例如:
- let a = {
- age: undefined,
- sex: Symbol('male'),
- jobs: function() {},
- name: 'yck'
- }
- let b = JSON.parse(JSON.stringify(a))
- console.log(b) // {name: "yck"}
借用 MessageChannel 实现深拷贝
MessageChannel API允许我们创建一个新的消息通道,并通过它的两个MessagePort属性发送数据。
- var channel = new MessageChannel();
这样就创建了一个管道。
实例属性:
- channel.port1
- channel.port2
获取实例的两个端口,注意的是,两个端口都是只读的。
简单来说,MessageChannel
创建了一个通信的管道,这个管道有两个端口,每个端口都可以通过postMessage
发送数据,而一个端口只要绑定了onmessage
回调方法,就可以接收从另一个端口传过来的数据。
一个简单的例子:
- var channel = new MessageChannel();
- var port1 = channel.port1;
- var port2 = channel.port2;
- port1.onmessage = function(event) {
- console.log("port1收到来自port2的数据:" + event.data);
- }
- port2.onmessage = function(event) {
- console.log("port2收到来自port1的数据:" + event.data);
- }
- port1.postMessage("发送给port2");
- port2.postMessage("发送给port1");
而通过 postMessage() 方法传输的 message 参数是深拷贝的。
- function deepClone(val) {
- return new Promise((resolve,reject) => {
- const {port1,port2} = new MessageChannel();
- port2.onmessage = e => resolve(e.data);
- port1.postMessage(val);
- })
- }
- let obj = {
- age: undefined,
- name: 'yck',
- c: {
- d: true
- }
- }
- obj.c.e = obj.c; // 循环引用
- // 注意该方法是异步
- async function test() {
- const clone = await deepClone(obj);
- console.log(clone) // {age: undefined, name: "yck", c: {…}}
- }
- test()
但这个深拷贝只能解决 undefined 和循环引用对象的问题,对于 Symbol 和 function 依然束手无策。
详细可参考:《MessageChannel 消息通道》
简易版的深拷贝
- var extendCopy = (function f(p,c){
- var c = c || {};
- for (var i in p) {
- if(typeof p[i] === 'object'){
- c[i] = (p[i] instanceof Array) ? [] : {};
- f(p[i],c[i]);
- }else{
- c[i] = p[i];
- }
- }
- return c;
- });
详细可参考:《小tips:JS之浅拷贝与深拷贝》
lodash 的深拷贝函数
语法:
- _.cloneDeep(value)
示例:
- var objects = [{ 'a': 1 }, { 'b': 2 }];
- var deep = _.cloneDeep(objects);
- console.log(deep[0] === objects[0]);
- // => false
地址:https://lodash.com/docs/4.17.15#cloneDeep
小tips:使用JSON.parse(JSON.stringify(object))实现深拷贝的局限及扩展的更多相关文章
- javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())
javascript 数组和对象的浅度复制和深度复制在平常我们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面我们看一个例子引用和复制是什么概念 var arr=[1,2,3,' ...
- JSON.parse(JSON.stringify()) 实现对对象的深拷贝
JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...
- 关于JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑
JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...
- 实现深拷贝还在用JSON.parse(JSON.stringify(obj))?带你用JS实现一个完整版深拷贝函数
使用JavaScript实现深拷贝 1.JSON序列化实现深拷贝 在JS中,想要对某一个对象(引用类型)进行一次简单的深拷贝,可以使用JSON提供给我们的两个方法. JSON.stringfy():可 ...
- 使用JSON.parse(),JSON.stringify()实现对对象的深拷贝
根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系. 测试例子: var test={ a:"ss", ...
- JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj)实现数组的深拷贝 利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象
- JSON.parse JSON.stringify
JSON.stringify() undefined 值.函数或者XML值会被忽略 数组当中含有 undefined值,函数或XML值,该数组中的这些值将会被当成 null 正则对象会被转成空对象 J ...
- 【Immutable】拷贝与JSON.parse(JSON.stringify()),深度比较相等与underscore.isEqual(),性能比较
样本:1MB的JSON文件,引入后生成500份的一个数组: 结果如下: 拷贝性能: JSON.parse(JSON.stringify()) 的方法:2523.55517578125ms immuta ...
- this.treeData = JSON.parse(JSON.stringify(this.d)) 树的序列化反序列化
this.treeData = JSON.parse(JSON.stringify(this.d))
- JSON.parse(JSON.stringify()) 实现对对象的深度拷贝,从而互不影响
JSON.parse(JSON.stringify({"key": "value"})) 根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字 ...
随机推荐
- window10设置开机自启动exe的三种方式(亲测有效)
拷贝文件到自启动位置 路径地址:C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp 通过组策略设置脚本随服务器启动 开始-> ...
- 部分解决 | ocrmypdf对中文pdf进行ocr识别后存在多余空格
1.问题 ocrmypdf安装采用的是在windows安装方法具体看 https://media.readthedocs.org/pdf/ocrmypdf/latest/ocrmypdf.pdf 由于 ...
- [oeasy]python0074[专业选修]字节序_byte_order_struct_pack_大端序_小端序
进制转化 回忆上次内容 上次 总结了 计算字符串值的函数 eval 四种进制的转化函数 bin oct int hex 函数名 前缀 目标字符串所用进制 bin 0b 二进制 oct 0o ...
- [oeasy]python0117 文字的演化_埃及圣书体_象形文字_楔形文字
埃及圣书体 回忆上次内容 两河流域 苏美尔文明 所使用的 楔形文字 不是象形文字 添加图片注释,不超过 140 字(可选) 楔形文字的字型 究竟是怎么来的呢? 巴别塔 苏美尔的 ...
- [oeasy]python0024_ 输出时间_time_模块_module_函数_function
输出时间 回忆上次内容 print函数 有个默认的 end参数 end参数 的值可以是任意字符串 end参数 的值会输出到结尾位置 end参数 的默认值是 ...
- oeasy教您玩转vim - 58 - # 块可视化
块可视化编辑 回忆上节课内容 上次我们了解到行可视模式 行可视模式 V 也可配合各种motion o切换首尾 选区的开头和结尾是mark标记 开头是 '< 结尾是 '> 可以在选区内进 ...
- 番外篇: go语言写的简要数据同步工具
go-etl工具 作为go-etl工具的作者,想要安利一下这个小巧的数据同步工具,它在同步百万级别的数据时表现极为优异,基本能在几分钟完成数据同步. 1.它能干什么的? go-etl是一个数据同步工具 ...
- Dubbo日志链路追踪TraceId选型
一.目的 开发排查系统问题用得最多的手段就是查看系统日志,但是在分布式环境下使用日志定位问题还是比较麻烦,需要借助 全链路追踪ID 把上下文串联起来,本文主要分享基于 Spring Boot + Du ...
- 系动词&使役动词
系动词 系动词的作用就是赋值 I am a rabbit 把 a rabbit赋值给i我 我是一只兔子 The rabbit is smart 这兔子是聪明的 smart赋值给兔子 系动词连系的方式, ...
- Mysql函数12-DATE_FORMAT
DATE_FORMAT函数用于日期格式的转换. 1.sql查询出一列create_time select create_time from goods where id=65 2.让create_ti ...