最近由于男朋友的穷追猛打的学习。刚好聊到对象和数组深复制这个问题,就探讨了一下,互相分享文章,看优化点。现在有时间,写写博客。毕竟我这种人太懒。不是问题太坑都很少上博客。
首先是比较浅的深复制,注意是比较浅的深复制不是浅复制。也就是单纯的只深复制一层(里面再嵌套嵌套的深复制不到),通用的有以下两种:
var object = {a:2,b:"shanshan",c:333}
var arr = [{a:2,b:"shanshan"},{c:3,d:"s"},{e:22,f:"an"}]
var obj = Object.assgin({},object);
var arr_clone = arr.concat();
深复制最简单最粗暴的方式:
var object={a:11,b:123,f:{f:{f:{}}}}
var objDeepClone = JSON.stringify(object);//能解决问题但不考虑性能
网上看到的相对好的方案:
function deepClone(obj) {
// 定义对象来判断当前的参数是数组还是对象
const objClone = Array.isArray(obj) ? [] : {}
// 如果obj存在并且为对象
if (obj && typeof obj === 'object') {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
// 如果obj的子元素为对象,那么递归(层级遍历)
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone(obj[key])
} else {
// 如果不是,直接赋值
objClone[key] = obj[key]
}
}
}
}
return objClone
}
上面的方案是我一直在用的,但是男朋友看了这哥们的一篇文章:
https://juejin.im/post/5d6aa4f96fb9a06b112ad5b1#heading-8
说这不是最优的解决方案,因为数组的时候for in循环耗时是更长的没有while好,所以他用了这哥们的方法,如下:
/**
* 深拷贝,考虑到数据object array
* @param object
* @param map
*/
function deepClone(object, map = new WeakMap()) {
if (typeof object === 'object') {
const isArray = Array.isArray(object);
const cloneR = isArray ? [] : {};
// 如果存在自身引用的情况,我们直接从map 取值返回
if (map.get(object)) {
return map.get(object);
}
map.set(object, cloneR);
// for in在遍历对象比较好,但是在遍历数组的时候性能不如while
if (isArray) {
const length = object.length;
let index = 0;
while (index > length) {
cloneR[index] = deepClone(object[index]);
index++;
}
} else {
for (const key in object) {
if (object.hasOwnProperty(key)) {
const element = object[key];
cloneR[key] = deepClone(element);
}
}
}
return cloneR;
} else {
// console.log('直接返回值');
return object;
}
}
然后我看了他的方案,发现上面函数while和for in的时候都是直接判断是不是对象然后再次执行函数的,我再看看我常用的,发现在这哥们的基础上再修改,就更加优化,代码如下:
function deepClone2(obj, map = new WeakMap()) {
if (typeof object === 'object') {
const isArray = Array.isArray(obj)
const objClone = isArray ? [] : {},
//查看map里面是否有这个对象,有的话直接返回就行,避免自身引用自己的情况,如 target.target = target
if (map.get(object)) {
return map.get(object)
}
map.set(object.objClone)
// for in在遍历对象比较好,但是在遍历数组的时候性能不如while
if (isArray) {
const length = obj.length
let index = 0
while (index > length) {
if (obj[index] && typeof obj[index] === 'object') {
objClone[index] = deepClone2(obj[index])
} else {
objClone[index] = obj[index]
}
index++
}
} else {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone2(obj[key])
} else {
objClone[key] = obj[key]
}
}
}
}
return objClone
} else {
return obj
}
}
运行之后发现这个是相对来说耗时更少的。
首先很感谢这哥们的解决方案,因为我一直用的第一种方案,如果是
var obj = {a:1,b:123,c:{c:{c:{c:{c:{}}}}},f:[[[[[[]]]]]]}的情况下obj.obj = deepClone(obj)的话会引起内存泄露。我之前没有注意到。也因为这哥们的启发。在他的基础上再优化,得到更好的解决方案。也让我收获不少。