JavaScript中的对象深拷贝

193 阅读1分钟

深度克隆(拷贝)

前言: 在上一篇文章开头的介绍中我们是不是说过对一个对象进行修改不会影响到另一个对象,但是很明显,在 浅度克隆 中对 obj1 中的sex改动的时候(因为sex是数组,是引用类型,为堆内存中的对象),obj2中的sex也随着改动了,这样就达不到我们想要的效果,所以深度克隆就是来解决这个问题的。

前提 : 深度克隆会稍微比较浅拷贝难一点,所以读这篇文章你要理解一下JavaScript中的 原型,还有以下几个方法的应用。

Object.hasOwnProperty(prop)

Object.prototype.toString()

Function.prototype.apply()

Function.prototype.call()

如何应用,可以到各大博客社区或者 MDN,javaScript高程设计 看看

例子:

<script type="text/javascript">
	//深度克隆:
	var obj = {
		name : 'abc',//(原始值)
		age : 18,//(原始值)
		card : ['visa','master'],//数组(引用值)
		wife : {//对象(引用值)
			name : 'Tom',
			son : {
				name: 'mySon'
			}
		}
	};
	var obj1 = {};
//遍历对象 for (var prop in obj) 数组也能for in (其中prop为索引值)
//1、判断是不是原始值typeof()
//2、判断是数组还是对象      
//3、建立相应的数组或对象

function deepClone(origin,target) {
	var target = target || {},
		toStr = Object.prototype.toString,//使用toString()检测对象类型
		arrStr = '[object Array]';
	for(var prop in origin){
		if (origin.hasOwnProperty(prop)) {//判断是不是原型上面的,如果是返回false
			if (origin[prop] !== 'null' && typeof(origin[prop]) == 'object') {
				if(toStr.call(origin[prop]) == arrStr){
				//判断是不是数组[object Array]
					target[prop] = [];
				}else{
					target[prop] = {};
				}
				deepClone(origin[prop],target[prop]);//递归操作
			}else{
				target[prop] = origin[prop];
			}
		}
	}
	return target;
}

//利用三目运算符简化代码,如下:
	function deepClone(origin,target) {
	var target = target || {},
		toStr = Object.prototype.toString,
		arrStr = '[object Array]';
	for(var prop in origin){//遍历对象
		if (origin.hasOwnProperty(prop)) {//判断是不是原型上面的,如果是返回false
			if (origin[prop] !== 'null' && typeof(origin[prop]) == 'object') {
				target[prop] = toStr.call(origin[prop]) == arrStr? [] : {};
				deepClone(origin[prop],target[prop]);//递归操作
			}else{
				target[prop] = origin[prop];
			}
		}
	}
	return target;
}
</script>

简化代码:

利用JSON对象中的 stringify()和parse() 方法

<script type="text/javascript">
	var book = {
	    title: "professional javaScript",
	    authors: [
	        "qietuzai",
	        "qietuzai"
	    ],
	    edition: 3,
	    year: 2019,
	    name: undefined, // 不会输出,只输出有效的JSON数据类型的实例属性
	};
	
	var copyBook = JSON.parse(JSON.stringify(book));
	console.log(copyBook);
	book.title = "我是一个基础数据类型";
	book.authors.push("我是一个引用数据类型");
	console.log(book);
</script>

存在问题:

  • 拷贝的对象的值有函数、undefined、symbol,JSON.stringify序列化后该键值对会消失
  • 拷贝Date类型引用类型会变为字符串
  • 无法拷贝不可枚举类型的属性
  • 无法拷贝对象的原型链
  • 拷贝RegExp引用类型会转变为空对象
  • 对象中含有NaN,Infinity,-Infinity,JSON.stringify的结果变成null
  • 不能拷贝对象的循环应用

参考: juejin.cn/post/700297…