对数组、对象进行深复制
大家曾否想过这样的问题:当你要对一个数组,或者对象进行复制的时候,怎么进行复制?
我们都知道,除了三种基本的数据类型外(Number,Boolean,String)的数据赋给另外一个变量的时候,这样该变量得到的不是这些数据的副本,而是一个指向该数据的引用,它的变化,会影响原来的数据对象。这可怎么得到这种数据对象的引用呢?
看下面的代码:
var arr1 = [ [1,2,3] , [1,2,3] , [1,2,3] ]; var arr2 = arr1; //arr2的改变会使arr1也同时改变 arr2[0] = 'replaced'; // arr2 = [ 'replaced' , [1,2,3] , [1,2,3] ]; // arr1 = [ 'replaced' , [1,2,3] , [1,2,3] ]; // arr2 === arr1; // This is TRUE
那下面用我们平时的做法来重新声明一个数组,通过循环来赋值:
var theCopy = []; // An new empty array
for (var i = 0, len = arr1.length; i < len; i++) {
theCopy[i] = arr1[i];
}
// &quot;theCopy&quot; = [ 'replaced' , [1,2,3] , [1,2,3] ]
但是大家注意到没有,arr1的第二和第三个元素还是一个数组,这样theCopy的第二第三个元素还是得到了arr1中相应位置的数组元素的引用,还是有关联。还没有实现深度赋值。接着看下面的代码:
function deepCopy(obj){
//如果obj是数组
if (Object.prototype.toString.call(obj) === '[object Array]') {
var out = [], i = 0, len = obj.length;
for (; i < len; i++) {
//arguments.callee == deepCopy
//当然可以用deepCopy代替arguments.callee
out[i] = arguments.callee(obj[i]);
}
return out;
}
//如果是对象
if (typeof obj === 'object') {
var out = {}, i;
for (i in obj) {
out[i] = arguments.callee(obj[i]);
}
return out;
}
return obj;
}
上面的deepCopy才真正的实现了深度复制,通过递归的技巧来循环遍历数组或者对象的每一个属性。这样就能够深入到数组或者对象的“里面”,实现真正的深度复制。
有些人或许会问这个方法有什么实际使用价值,当然,这样做的人其实不多,但是当你需要使用一个已经存在的数组里的数据,而又不想因为操作这些数据的时候改变原来数组的元素内容,这个时候你就需要得到数组的副本,而不是引用了。