一、JSON序列化
在js中使用深拷贝的方法有几种,一般常用JSON.parse(JSON.stringstry())的方法克隆数据,但是这个方法也是有缺陷的:
1、对象中有NaN、Infinity和-Infinity的时候,序列化之后会变成null。
2、对象中有undefined和Function类型数据的时候,序列化之后会直接丢失。
3、对象中有时间类型的时候,序列化之后会变成字符串类型。
4、对象循环引用的时候,序列化之后会直接报错。
例如:
const obj = {
nan:NaN,
infinityMax:1.7976931348623157E+10308,
infinityMin:-1.7976931348623157E+10308,
undef: undefined,
fun: () => { console.log(123) },
date:new Date,
wife:obj.name
}
二、使用 new MessageChannel 通信克隆数据
new MessageChannel的介绍:
- 通过构造函数 MessageChannel() 可以创建一个消息通道,实例化的对象会继承两个属性:port1 和 port2
- port1 和 port2 都是 MessagePort 对象,在这里是只读的,无法对其进行字面量赋值
- MessagePort 对象具有 onmessage 和 onmessageerror 两个属性
- 这是两个回调方法,使用 MessagePort.postMessage 方法发送消息的时候,就会触发另一个端口的 onmessage
- 消息通道就像是一条左右贯通的管道,左右两个端口就是 port1 和 port2,这两个端口可以相互发送消息,port1 发送的消息可以在
port2 接收到,反之亦然
// 深拷贝函数
function deepClone(val) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel()
port2.onmessage = e => resolve(e.data)
port1.postMessage(val)
})
}
// 定义一个包含 undefined 的对象
let obj = {
a: 'wise',
b: undefined,
c: {
d: 'wrong'
}
}
// 循环引用
obj.c.e = obj.c
// 注意该方法是异步的
async function test() {
const clone = await deepClone(obj)
console.log(clone)
}
test()
但这个深拷贝只能解决 undefined 和循环引用对象的问题,对于 Symbol 和 function 依然束手无策
三、使用递归的方法克隆
使用递归的方法克隆一个数据,建议将此方法封装在一个文件内去调用;
deepClone(obj) {
//创建一个新的 Map 对象。其是一种键值对的集合,其中的键是唯一的,值可以重复。
const objectMap = new Map();
const _deepClone = (value) => {
const type = typeof value;//获取数据的类型
//判断数据的类型是否是 null 或者不是 object
if (type !== 'object' || type === null) {
return value;
}
// 判断map中是否已经存在当前value的值
if (objectMap.has(value)) {
return objectMap.get(value)
}
//判断当前的value是否为数组或者object,且根据情况返回空对象或者空数组
const result = Array.isArray(value) ? [] : {};
//新建空的对象或者数组
objectMap.set(value, result);
//循环递归赋值
for (const key in value) {
result[key] = _deepClone(value[key])
}
return result
}
return _deepClone(obj);
}
拓展new Map():
- set(key, value) : 向 Map 对象中添加一个键值对。
- get(key) : 获取指定键对应的值。
- has(key) : 判断 Map 对象中是否存在指定的键。
- delete(key) : 删除指定键及其对应的值。
- size : 返回 Map 对象中键值对的数量。
- clear() : 清空 Map 对象中的所有键值对。
- keys() : 返回一个包含 Map 对象中所有键的迭代器。
- values() : 返回一个包含 Map 对象中所有值的迭代器。
- entries() : 返回一个包含 Map 对象中所有键值对的迭代器。