从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性。
在复制对象时,除了要复制对象的属性外,还要兼顾到是否保留了对象的构造函数属性,是否对每一种数据类型(JavaScript常见的数据类型有字符串、数字、布尔值、数据,正则表达式,数组,函数,对象)都实现正确的复制。项目中,我们可以根据实际情况,决定需要实现什么样程度的复制。
本文是我在复制对象方面的一些心得总结,由浅复制到深复制,由只复制简单属性到复制功能、正则表达式等复杂属性,层层递进。如有陈述不当之处,烦请指出,不胜感激。
<强>浅复制强>
浅复制只会依次复制对象的每一个属性,不会对这些属性进行递归复制。下面是一个简单的浅复制实现。
//对象浅复制 函数shadowCopy (obj) { 如果(typeof obj !=='对象')返回obj; (var道具obj) { 如果(obj.hasOwnProperty(道具)){ newObj[支持]=obj(道具); } } 返回newObj; }
仔细观察,不难发现上述方法的缺陷:
1。不能正确实现数组的浅复制
2。复制操作丢失了对象的构造函数属性
好,我们现在已经发现了问题所在,只需针对性地解决,一个还算完美的浅复制对象的方法就诞生了!
//对象浅复制 函数shadowCopy (obj) { 如果(typeof obj !=='对象')返回; var newObj;//保留对象的构造函数属性 如果(obj。构造函数===数组){ newObj=[]; 其他}{ newObj={}; newObj。构造函数=obj.constructor; } (var道具obj) { 如果(obj.hasOwnProperty(道具)){ newObj[支持]=obj(道具); } } 返回newObj; }
浏览器中测试一下:
var arr1=(0, 1, 2); console.log (arr1); console.log (shadowCopy (arr1)); var arr2=[0, 1, 2, [3、4、5]], arr2Copy=shadowCopy (arr2); console.log (arr2); console.log (arr2Copy); arr2Copy [3] [0]=6; console.log (arr2 [3] [0]);//6
好!可以正确实现数组复制和并且保留构造函数了,但细心的你一定发现了,浅复制后的对象的arr2Copy[3]和arr2[3]指向的是一个对象,改变其中一个,同时也会改变另一个。我们想要实现的是复制,但这并不是复制呀!
这是浅复制的一个弊端所在,接下让我们看看深复制是怎样解决这个问题的。
<强>深复制强>
深复制需要层层递归,复制对象的所有属性,包括对象属性的属性的属性....(晕~)
如果只是需要简单地复制对象的属性,而不用考虑它的构造函数,也不用考虑函数,正,则数据等特殊数据类型,那这里有一个深复制的小技巧,两行代码即可:
函数deepCopy (obj) { 如果(typeof obj !==岸韵蟆?{返回;} var str=JSON.stringify (obj); 返回JSON.parse (str); }
大多数情况下,上面的就可以满足要求了,但一些时候,我们需要把函数,正则等特殊数据类型也考虑在内,或者当前环境不支持JSON时,上面的方法也就不适用了。这时,我们可以通过递归来实现对象的深层复制,如下:
函数deepCopy (obj) { 如果(typeof obj !==岸韵蟆?{返回;} var newObj;//保留对象的构造函数属性 如果(obj。构造函数===数组){ newObj=[]; 其他}{ newObj={}; newObj。构造函数=obj.constructor; } (var道具obj) { 如果(typeof obj[支持]==='对象'){ 如果(obj[支持]。构造函数===RegExp | | obj[支持]。构造函数===日期){ newObj[支持]=obj(道具); 其他}{//递归 newObj[支持]=deepCopy (obj[支持]); } 其他}{ newObj[支持]=obj(道具); } } 返回newObj; }
先用上面的例子测试:
棒!可以正确实现多维数组的复制,再看是否能实现函数和正则的复制: