使用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))实现深拷贝的局限及扩展的更多相关文章

  1. javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())

    javascript 数组和对象的浅度复制和深度复制在平常我们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面我们看一个例子引用和复制是什么概念 var arr=[1,2,3,' ...

  2. JSON.parse(JSON.stringify()) 实现对对象的深拷贝

    JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...

  3. 关于JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑

    JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...

  4. 实现深拷贝还在用JSON.parse(JSON.stringify(obj))?带你用JS实现一个完整版深拷贝函数

    使用JavaScript实现深拷贝 1.JSON序列化实现深拷贝 在JS中,想要对某一个对象(引用类型)进行一次简单的深拷贝,可以使用JSON提供给我们的两个方法. JSON.stringfy():可 ...

  5. 使用JSON.parse(),JSON.stringify()实现对对象的深拷贝

    根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系. 测试例子: var test={ a:"ss", ...

  6. JSON.parse(JSON.stringify(obj))

    JSON.parse(JSON.stringify(obj)实现数组的深拷贝 利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象

  7. JSON.parse JSON.stringify

    JSON.stringify() undefined 值.函数或者XML值会被忽略 数组当中含有 undefined值,函数或XML值,该数组中的这些值将会被当成 null 正则对象会被转成空对象 J ...

  8. 【Immutable】拷贝与JSON.parse(JSON.stringify()),深度比较相等与underscore.isEqual(),性能比较

    样本:1MB的JSON文件,引入后生成500份的一个数组: 结果如下: 拷贝性能: JSON.parse(JSON.stringify()) 的方法:2523.55517578125ms immuta ...

  9. this.treeData = JSON.parse(JSON.stringify(this.d)) 树的序列化反序列化

    this.treeData = JSON.parse(JSON.stringify(this.d))

  10. JSON.parse(JSON.stringify()) 实现对对象的深度拷贝,从而互不影响

    JSON.parse(JSON.stringify({"key": "value"})) 根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字 ...

随机推荐

  1. 全网最适合入门的面向对象编程教程:14 类和对象的 Python 实现-类的静态方法和类方法,你分得清吗?

    全网最适合入门的面向对象编程教程:14 类和对象的 Python 实现-类的静态方法和类方法,你分得清吗? 摘要: 本文主要介绍了Python中类和对象中的类方法和静态方法,以及类方法和静态方法的定义 ...

  2. redis基本数据结构-集合set

    redis基本数据结构-集合set 特性 一个集合键最多存储 2^32 - 1 个字符串值 元素在集合内无序(哈希表-链地址法解决冲突) 元素在集合内唯一 向集合添加元素 sadd key value ...

  3. [oeasy]python0011 - python虚拟机的本质_cpu架构_二进制字节码_汇编语言

    ​ 程序本质 回忆上次内容 我们把python源文件 词法分析 得到 词流(token stream) 语法分析 得到 抽象语法树(Abstract Syntax Tree) 编译 得到 字节码 (b ...

  4. Win10下安装LabelImg以及使用--LabelImg

    labelImg是图片标注软件,用于数据集的制作.标注等等.下面介绍labelImg的安装过程. 我用的是anaconda,所以以anaconda prompt作为终端: 在Anaconda Prom ...

  5. 面试题-python 什么是装饰器(decorator )?

    前言 python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象.很多python初学者学到面向对象类和方法是一道大坎,那么py ...

  6. java+mysql+tomcat环境变量配置(windows版)

    jdk8(本人用的jdk8) 系统变量->新建:{JAVA_HOME=[JDK安装目录]} 系统变量->PATH:头部追加%JAVA_HOME%\bin;%JAVA_HOME%\jre\b ...

  7. Codeforces Round 953 (Div. 2)

    Codeforces Round 953 (Div. 2) 闲来无事水题解. A . B . C 显然 \(k\) 是偶数.考虑 \(k\) 的上界,\(p_{1}=n,p_{n}=1\),产生 \( ...

  8. Zabbix 5.0 LTS 配置企业微信(Webhook)自动发送告警信息

    依据前面文章<Zabbix 5.0 LTS URL 健康监测>环境,实现企业微信(Webhook)自动发送告警信息. 一.创建企业微信机器人 先在自己的企业微信群里创建一个机器人,并获取其 ...

  9. IDL根据Landsat QA波段去云处理【代码】

    IDL根据Landsat QA波段去云处理[代码] ​ landsat QA波段(质量评估波段)是Landsat卫星影像数据中的一个特殊波段,他在Landsat5-9的每个产品中都存在.虽然我们常用的 ...

  10. 【Spring】01 快速入门

    Spring快速入门 空Maven项目创建 声明工程名称,完成 删除SRC目录,创建01 HelloSpring模块 导入依赖 Maven坐标: <!-- https://mvnreposito ...