对象浅谈深复制

最近由于男朋友的穷追猛打的学习。刚好聊到对象和数组深复制这个问题,就探讨了一下,互相分享文章,看优化点。现在有时间,写写博客。毕竟我这种人太懒。不是问题太坑都很少上博客。

首先是比较浅的深复制,注意是比较浅的深复制不是浅复制。也就是单纯的只深复制一层(里面再嵌套嵌套的深复制不到),通用的有以下两种:

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)的话会引起内存泄露。我之前没有注意到。也因为这哥们的启发。在他的基础上再优化,得到更好的解决方案。也让我收获不少。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值