深拷贝要先对被拷贝的对象的属性判断是否是对象,如果是对象的话还要对再判断子对象的属性是否有对象,如果有的话,还要再次验证,直到所有子对象的属性都不是对象位置。
所以深拷贝的的复杂点在于不知道要拷贝的对象嵌套了多少层对象。在这种时候,调用自身的函数就十分管用。
起初自己写的代码为:
var testObj = {memStr:'I am a string', memArr:['string',{change:'try change me'},1], memNum:1, memObj:{test:'old value'} }; function deepCopy (obj){ var newo = {}; for(var key in obj){ var copy = obj[key]; if(typeof copy === 'object'){ newo[key] = arguments.callee(copy); }else{ newo[key] = copy; } } return newo; }
测试testObj之后发现,里面的数组在拷贝之后变成了对象,即memArr{1=‘string’,2=……}诸如此类的“对象化”的数组。所以,对于对象和数组要分别处理,最直接的办法就是直接为拷贝的结果创建一个空的对象/数组。而且因为typeof对于对象和数组都返回'object',所以object就不管用了,我们可以尝试对象原型的toString方法。
这是改进之后的代码:
1 function deepCopy (newObj,obj){ 2 var toString = Object.prototype.toString 3 for(var key in obj){ 4 var value = obj[key]; 5 if(toString.call(value).slice(8,-1) === 'Object'){ 6 newObj[key] = arguments.callee(newObj[key]||{},value); 7 } 8 else if(toString.call(value).slice(8,-1) === 'Array'){ 9 newObj[key] = arguments.callee(newObj[key]||[],value); 10 } 11 else{ 12 newObj[key] = obj[key]; 13 } 14 } 15 return newObj; 16 }
这就解决了数组“对象化”的问题。