被滥用的for in循环
众所周知,javascript中有两种for循环,一种是:
var a=['this','is','a','article'], i, len; for( i = 0,len = a.length;i < len; i++ ){ console.log(a[i]); }
另一种是for in循环,形如:for (item in arr){...}
for in 循环是用在遍历一个Object的key的时候可用到的,而第一种for循环是专门用来遍历数组里面的元素,如果滥用for in循环将会导致一些不可预料的结果。
在项目中,我们有一个函数叫做:toggleSelectionAll(arr1,arr2):
var a = [], b = [1,2,3,4,5,6]; var toggleSelectionAll = function(arr1,arr2){ if(Array.isArray(arr1) && arr1.length === arr2.length){ arr1.splice(0,arr1.length); //反选 }else if(Array.isArray(arr1)){ //全选 var item ; for(item in arr2){ arr1.push(item); } } }; toggleSelectionAll(a,b);
toggleSelectionAll的功能是实现一个类似于全选和反选的功能,但是很不幸它用了for in,所以我们就会看到全选之后的a:
["0", "1", "2", "3", "4", "5"]
这完全是错的。很快写代码的人就意识到了问题所在,原来他应该将arr1.push(item) 改成arr1.push(arr2[item]);
这一次全选之后得到了如下结果的a:
[1, 2, 3, 4, 5, 6]
这个结果是正确的。
但是又一个问题来了,这时候,有人在某段代码中加了这么一句:
Array.prototype.sayHi= function(){
console.log('Hi~ ');
}
这时候当再次执行全选操作的时候,得到的a如下:
[1, 2, 3, 4, 5, 6, function (){
console.log('hi');
}]
什么情况??我只想要1,2,3,4,5,6啊 怎么多出来一个函数?这不仅导致a里面的数据出错,还会导致当下次反选的时候失效,因为这时候a.length !== b.length。
很明显,它就是sayHi这个函数。因为在Array.prototype中加入了这个属性,而for in循环是遍历整个数组的属性,将enumerable(表示属性是否可以被枚举)为true的属性拿出来,默认情况下,增加一个属性,那么该属性是可以被枚举的。所以很明显,就能拿到sayHi。
总的来说,这是因为对for in的滥用造成的。for in循环不应该用在遍历数组。应该用for(i=0;i<len;i++)的形式,或者用Array.forEach()的形式来做这件事。