I was surprised when I was able to reproduce a bug with a minimum amount of code. Note that in this minimalist example Array.indexOf isn't being called. Also note that I've tried several different implementations of indexOf, including several from stackoverflow.com.
The bug is, when the for...in executes in IE, three alerts are displayed: "indexOf", "0", and "1". In FF, as one would expect, only two ("0", "1") appear.
<html>
<body onLoad="test();">
<script language="javascript">
var testArray = ['Foo', 'Bar'];
if(!Array.prototype.indexOf) {
Array.prototype.indexOf = function (obj, fromIndex) {
if (fromIndex == null) {
fromIndex = 0;
} else if (fromIndex < 0) {
fromIndex = Math.max(0, this.length + fromIndex);
}
for (var i = fromIndex, j = this.length; i < j; i++) {
if (this[i] === obj)
return i;
}
return -1;
};
}
function test() {
var i;
for(i in testArray) {
alert(i);
}
}
</script>
</body>
</html>
Can anyone explain this? I've already changed my code to use a while
so I'm not under the gun, but this one really has me stumped. It reminds me of memory overrun errors in c.
See "for in Intrigue" on the Yahoo! User Interface blog.
The reason your code is working as expected in Firefox is because you haven't added your own indexOf
method in Firefox. The for in
loop iterates over all the keys in the object's prototype chain, including the indexOf
method you added. Douglas Crockford suggests the following solution:
for (var p in testArray) {
if (testArray.hasOwnProperty(p)) {
alert(testArray[i]);
}
}
Alternatively, you can just filter out functions:
for (var p in testArray) {
if (typeof testArray[p] !== "function") {
alert(testArray[i]);
}
}
Also, as "nickf" points out, it is best not to use the for in
loop for iterating over arrays. The for in
loop is intended for iterating over the keys in an object.
Steve
for .. in
is meant for looping through object properties, definitely not arrays.
Stick to the standard:
for (var i = 0, l = myArray.length; i < l; ++i) { .. }
More info at the Mozilla Developer Centre:
A for...in
loop does not iterate over built-in properties. These include all built-in methods of objects, such as String's indexOf method or Object's toString method. However, the loop will iterate over all user-defined properties (including any which overwrite built-in properties).
Although it may be tempting to use this as a way to iterate over an Array, this is a bad idea. The for...in statement iterates over user-defined properties in addition to the array elements, so if you modify the array's non-integer or non-positive properties (e.g. by adding a "foo" property to it or even by adding a method or property to Array.prototype), the for...in statement will return the name of your user-defined properties in addition to the numeric indexes.