在深入探讨前,例子是必须的,只有在例子中我们才能更深入的理解这一点,就拿最常见的数组对象来说吧
实例1:
function getArray(){
var array=[1,2,3,4,5];
var result = [];
for(var i=0;i<array.length;i++){
result.push(array[i]);
}
alert(result.join(''));
}
这段代码应该没有任何难度,我们在调用函数的时候可以轻松的得到12345的字符串,如果这都看不懂,那只能说你的js是零入门了
实例2:
function getNewArray(){
var array=[1,2,3,4,5];
Array.prototype.age=13;
var result = [];
for(var i=0;i<array.length;i++){
result.push(array[i]);
}
alert(result.join(''));
}
第二个例子和第一个例子稍微有点不同,我们在数组的原型对象上定义了一个新的属性,这样所有的数组都会有这个属性,但是我们在下面用for循环的时候却并没有将这个值打印出来(这并不稀奇,打印出来才见鬼了)
实例3:
function getArrayTwo(){
var array=[1,2,3,4,5 ];
var result=[];
for(var i in array){
result.push(array[i]);
}
alert(result.join(''));
}
这次我们没有再用for循环了,而是采用了for in循环,但是给我们期望的一样还是得到了12345的正确结果
实例4:
function getNewArrayTwo(){
var array=[1,2,3,4,5 ];
Array.prototype.age=13;
var result=[];
for(var i in array){
result.push(array[i]);
}
alert(result.join(''));
}
注意,这次可有区别了,我们再次给Array.prototype上面增加了一个原型属性,这次我们换成for in循环去遍历这个数组,奇怪的事情发生了,既然最后的结果是1234513。为什么呢?为了了解其中的原因,我们有必要要先着重讨论下在执行for in的时候,javascript内部到底发生了什么
我们在执行for in循环的时候,可以获得对象的可枚举属性,for和in中间的值是属性的名字,in后边的是对象。然后执行循环体。只要该对象还有更多的可枚举属性,并且在循环体中没有出现过break,continue这些关键字的话,这个过程就将不断重复,直到我们把所有的属性遍历完。
对于上面的数组而言,唯一可枚举属性是它的下标(即0,1,2,3,4)。它原型上默认提供的length属性等等都不可枚举。这就是为什么for in循环仅仅揭示了它的下标和这些下标相关联的值。然而,当我们向某个对象,或者在其原型链上添加了属性的时候, 那么它们在默认情况下是可枚举的,这也是为什么上面第4个例子会出现与我们期望的结果相反的原因
所以建议不要对数组执行for in循环,事实上,在高性能javascript这本书中,也强调了for in循环的不好,因为它总是会访问该对象的原型,看下原型上是否有属性,这在无意中就给遍历增加了额外的压力。有兴趣的朋友,我向大家推荐这本书,因为这是一本讲js性能方面不可多得的好书
虽然for in循环在此处改变了我们的预期行为,但是它并不是不可解决的,javascript中得hasOwnProperty这个方法专门是为解决这个方法而生的
如果某个对象具有给定名称的属性,那么Object.prototype.hasOwnProperty(name)返回true。如果该对象是从原型链中继承了该属性,或者根本没有这样的一个属性,则返回false。这就意味着我们可以很轻松的控制hasOwnProperty限定for in循环在当前中遍历,而不用去考虑它的原型属性
改进上面实例4的方法如下:
function finalArray(){
var array=[1,2,3,4,5 ];
Array.prototype.age=13;
var result=[];
for(var i in array){
if(array.hasOwnProperty(i)){
result.push(array[i]);
}
}
alert(result.join(''));
}
通过对array使用hasOwnProperty判断当前的i属性是否是该对象的属性,如果是加入到数组中,否则过滤,这样就避免了去寻找原型属性
但是在使用这个方法的时候有两点需要铭记:
1.有一部分浏览器,例如早起的safari浏览器,不支持这个方法
2.对象经常被用作哈希值,这就是存在hasOwnProperty被另外的属性屏蔽的风险(但是我估计没有人那么无聊使用这个属性)
文章结尾的时候再对for in和for循环在这里稍微的说一下,经常见到有文章在讨论对for in循环和for循环的性能比较,但是基本都不统一, 这给很多学习javascript的朋友来说是一个灾难。在这里我给大家的建议是,尽量避免用for in循环,除非你有必要的把握必须使用,当然希望大家不要被我的这各话就拒绝使用for in循环,要自己多做下测试才是正确的,因为只有自己执行后看到的代码才是最真实的