问题:
很多时候,我们会有这样一个需求,我们定义了一个数组。但是我们需要拷贝一份数组备份出来做其他操作。原数组保留不变。
这里我将提出3个方法,并对某一个方法进行说明。这里会遇到一个很有意思的问题。就是值引用和地址引用的问题,并进行说明。
想法:
这里有三种想法:
1、遍历数组,将每一个数组元素(n层也是如此)。赋值到另一个新建数组。
2、自定义Array.prototype.Clone(){}方法,自己写方法体内容。
3、讨巧的使用默认方法concat()来实现。
分析:
1、方法1,显然不是可取的建议。又或者说对于追求编程艺术的我来说,这不是最推荐的。当然这并不代表他不能解决问题。
2、方法2,这是一个比较有趣的写法。代码如下:
function Array.prototype.clone(){
var tmp=new Array();
for(ob in this)tmp[ob]=this[ob];
return tmp;
}
它确实会将数组元素拷贝一份给另一个数组。但是这里是会有问题的,或者说它会有一个有趣的地方。等下衍生分析里有说到。
3、方法3,这是一个很有意思的方法,对于这个方法的两个说明是“这项方法会合并两个或更多的数组。”、“这项方法会合并多个字符串成一个新的字符串,并将新的字符串当作返回值。”。这个方法的一个典型的应用是:
arr1 = [1, 2, 3];
arr2 = [];
arr2 = arr2.concat(arr1);
它也的确能拷贝一份数组给另一个数组。当时它依然会发生一些有趣的现象。等下衍生分析里会有说到。
它完成了吗?对于数组拷贝的进一步分析。
这里我们提出一个假设,即:1、当数组是一个二维的数组,2、当数组元素不是值类型。那么当数组拷贝的时候,它拷贝了什么?
这里我们主要尝试使用方法3来验证下。我们构建一个二维数组。
arr1 = [["abc1","abc2","abc3"],["abc1","abc2","abc3"],["abc1","abc2","abc3"]];
arr2 = [];
arr2 = arr2.concat(arr1);
arr1[0][0] = "not abc1";
alert(arr1);
alert(arr2);
arr1.shift();
alert(arr1);
alert(arr2);
说明:这两个都是二维数组,数组元素都不是值类型。当我执行arr1[0][0] = "not abc1";以后,arr2[0][0]的值也改变了。这个可以通过前两个alert()发现。而当我arr1.shift()之后,alert()的内容却发生了变化。
为什么呢?
有一个认识是这样的,1、arr1和arr2的第一维存放的其实是第二维的引用。而第二维则实际存放他们的内容。这样当使用arr1修改某一个具体 的第二维元素时,arr2实际将会使用的值也是那个经过修改的过的第二维数组。2、这两个数组的第一维引用确实不是同一个。图过用堆栈图来模拟的话,差不 多应该是如下这张图:
这样的话,应该就可以清晰的理解了1、为什么修改arr1[0][0]的值,arr2会变化。2、为什么arr1.shift()之后,alert()的值不一样。
最后一些反省
这个如果换作其他语言,应该是不会搞错的。到底没有很基础的学过js原理,这些问题,其实java,.net语系的基本概念都有说明过。
要好好学啊~~。
http://hi.baidu.com/gantianamin2001/blog/item/ff9a3af4b14e57dff3d3855d.html