JavaScript 使用 for 循环时出现的问题

javascript 这个问题的讨论最初来自公司内部邮件,我只是把这个问题的讨论内容记录下来。

有一些项目组在定位问题的时候发现,在使用“for(x in array)”这样的写法的时候,在 IE 浏览器下,x 出现了非预期的值。

具体说,如果自定义了 Array.prototype.indexOf 方法(譬如源于某 prototype 污染),也许是因为老版本 IE 浏览器并不支持 array.indexOf 方法,而开发者又很想用,那么这样的浏览器可能会出现这样的问题:

Array.prototype.indexOf = function(){...};
var arr = [1, 2];
for (x in arr) console.log(x);

//会输出

1
2
function(){…}

换句话说,把 indexOf 这个方法给输出出来了。

解决方法很简单,要么别添加这个方法,要么用“for (i=0; i < array.length; i++)”这样的循环等等。

但是问题的本质呢?有人猜测,可能是因为 for(x in obj) 这种用法其实是去遍历一个对象,而 array 的实现其实也和普通的 object 一致,只不过 key 是既定的数值而已:

{0:"something", 1:"something else"}

一则 stackoverflow 的问答 里面也提到了,遍历数组的时候用 for…in 和 for(;;) 的区别,前者的含义是枚举对象的属性,存在这样两个问题:

  • 枚举的顺序无法被保证;
  • 继承属性也被枚举出来;

在对 Array.prototype.forEach 的支持上,从 这张表 中也可以明确看到,IE8 及以下版本是无法准确支持的:

image

这里 还有对 forEach 方法兼容性的详细阐述。事实上,主要的 JavaScript 框架(比如 jQuery、Underscore 和 Prototype 等等)都有安全和通用的 for-each 功能实现。

JSLint 的 for in 章节 里面也提到,for in 语句允许循环遍历对象的属性名,但是也会遍历到那些通过原型链继承下来的属性,这在很多情况下都会造成预期以外的错误。有一种粗暴的解决办法:

for (name in object) { if (object.hasOwnProperty(name)) { .... } }

还有人提到了使用 for(var i=0;i<length;i++) 类似这样的循环时的问题,因为 JavaScript 没有代码块级别的变量,所以这里的 i 的访问权限其实是所在的方法。有的书上会建议程序员把这样的变量声明放到一处去,但是从直观性上说,在大部分情况下都不够合理。使用 JavaScript 1.7 中引入的“let” 可以解决这个问题,使 i 成为真正的代码块级别的变量:

for(let i =0; i < a.length; i++)

最后,在 Google 的 JavaScript 风格导引里面, 也涉及到了这个约束

for-in loop:
Only for iterating over keys in an object/map/hash

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

10,672 次阅读

4 thoughts on “JavaScript 使用 for 循环时出现的问题

  1. Javascript 这个问题确实很烦人。let 语句那个是 Firefox 的私有实现,Chrome 是不支持的。Firefox 还内建 Iterator 对象来重新包装对象属性,使之像 for in 对数组和当字典用的对象操作起来像其它语言的做法。还有个简写语句 for of
    当然这些私有 api 只能写 Firefox 扩展用一下,一般页面貌似目前还是得老实用下标法。
     

发表评论

电子邮件地址不会被公开。

back to top