您的位置:首页 > Web前端 > JavaScript

对javascript中的for in循环和for循环的深入讨论

2013-08-03 18:17 309 查看
for in循环是js中一个比较特殊循环的案例,当我们给一个对象添加新的属性的时候,这个属性就可以被枚举出来。但是有时候for in循环的执行效果可能和我们期待的不一样,尤其是在该对象上添加了原型属性的时候会导致实际效果相反的一方面

在深入探讨前,例子是必须的,只有在例子中我们才能更深入的理解这一点,就拿最常见的数组对象来说吧

实例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循环,要自己多做下测试才是正确的,因为只有自己执行后看到的代码才是最真实的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: