对象
var obj = {
a字符串: "第一层",
b数值: 1,
c无穷大: Infinity,
dNaN: NaN,
e正则: new RegExp(/ab+c/, 'i'),
fNull: null,
g空对象: {},
h: true,
iUndefined: undefined,
j: [1,'a',{a:1},obj],
k2:{
a: '第二层',
b: 'bbb',
c3:{
a:'第三层',
b:1,
c4:{
a:'第四层',
b5:{
a:'第五层'
}
}
},
}
}
// 一个简单的环引用
var huan = {}
huan.a = huan
黄金:JSON.parse(JSON.stringify())
代码
function deepClone(target) {
return JSON.parse(JSON.stringify(target))
}
不足
参考文章说环引用报错,这里倒是没发现,环引用的字段直接就是一整个消失不见
其他需要注意的就是:
无穷大、NaN会变成null正则会变成空对象undefined会让字段消失环引用导致报错
内层对象如何拷贝
再看对象里的对象是深拷贝还是仅仅拷贝的地址:
OK,可以看到,对象里的对象也是深拷贝
遇到环会怎么样
报错呀
铂金:遍历对象
铂金初级
代码
function deepClone(target) {
const temp = {}
for (const key in target) {
temp[key] = target[key]
}
return temp
}
不足
- ok,我们可以看到,
环引用会变成undefied 正则、null会变成对象(看样子好像还是空对象)
除此之外似乎就没有了。
内层对象如何拷贝
那,内层的对象,是深拷贝还是浅拷贝呢?
看到这里就没必要再接着看下去了,这里可以看到关于对象,我们拷贝的仅仅是地址引用
遇到环会怎么样
遇到环之后,它拷贝的也仅仅是第一层的地址引用罢了
这是为什么呢?因为我们的函数,仅仅识别了第一层对象,第一层对象里仅仅保存对象的引用,那它拷贝的也就是引用了。
怎么解决呢?递归!遇到对象就递归!
铂金plus:递归
代码
function deepClone(target) {
// 基本数据类型直接返回
if (typeof target !== 'object') {
return target
}
// 引用数据类型特殊处理
const temp = {}
for (const key in target) {
// 递归
temp[key] = deepClone(target[key])
}
return temp
}
遇到环之后会怎样
一整个就是报错的大动作啊,因为环引用递归不完的
内层对象如何拷贝
这次在看内层对象:
很棒呀!这次都是深拷贝了!
但是……似乎有些不对呀!
我们看看拷贝出来的对象的j属性:
嗯.......
怎么是个对象呢?我们的j一开始不是个数组吗?怎么回事?
可以看代码里面,我们仅仅进行了是不是对象的判断,而typeof对引用数据类型进行判断是没那么准确的,所以,为了稍微更加精确点🤏 ,我们需要再加上一个数组的判断!
钻石:加入数组拷贝
下面这个代码,跟上面那段比起来,仅有一行进行了改变
function deepClone(target) {
// 基本数据类型直接返回
if (typeof target !== 'object') {
return target
}
// 引用数据类型特殊处理
// 判断数组还是对象
const temp = Array.isArray(target) ? [] : {} // *** 仅对这行进行了修改 ***
for (const key in target) {
temp[key] = deepClone(target[key])
}
return temp
}
我们可以看到,j属性存放的,已经变成数组了:
星耀:解决环引用
上面我们一直没有解决环引用。
其实环引用使用递归解决是会爆栈的,我这里不知道是因为书写不规范还是其他什么原因,要不然是undefined要不然就是整个字段消失不见
但不管怎么说,环引用我们一直没有解决。
问题不能放那里不动,问题是需要解决的!
Map
怎么解决呢?Map!
什么是Map呢?我们先来看:
Map的每一项都是一组键值对,
一个Map就是一组键值对的集合。
如果有其中也不会有重复的键。如下:
那我们就可以利用Map中不会有重复的键这一特性,来注册对象。
比如这里有一个对象obj,我们存放在map中:
如果我们看到对象,就从这个Map中的key中寻找有没有相同名字的对象,
如果有,那么就是环引用,直接放Map中对应的value,
如果没有,那就是没有见过的对象,新创建一个对象。
代码
function deepClone(target, map = new Map()) {
// 基本数据类型直接返回
if (typeof target !== 'object') {
return target
}
// 引用数据类型特殊处理
// 判断数组还是对象
const temp = Array.isArray(target) ? [] : {}
/* + */ if (map.get(target)) {
/* + */ // 已存在则直接返回
/* + */ return map.get(target)
/* + */ }
/* + */ // 不存在则第一次设置
/* + */ map.set(target, temp)
for (const key in target) {
// 递归,递归的时候,我们将最外层创建的map也传递进去,这样一个对象树,只会有一个最开始创建的map
temp[key] = deepClone(target[key], map)
}
return temp
}
勇者终将战胜恶龙!!!
内层对象如何拷贝
内层对象也是深拷贝呀!!!
王者:全数据类型覆盖
当然,这种我暂时也用不到,暂时先不看了,但是参考文章中有这部分内容,可以跳过去看一看~