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
indexOfmethod in Firefox. Thefor inloop iterates over all the keys in the object's prototype chain, including theindexOfmethod 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 inloop for iterating over arrays. Thefor inloop is intended for iterating over the keys in an object.Steve
overslacked : Thank you kindly; that's exactly what I needed.nickf : You really shouldn't be using for..in on arrays at all. See the link in my answer.Tomalak : @Steve: Since there is nothing broken, I wouldn't call using "hasOwnProperty()" a fix. ;-)Steve Harrison : @Tomalak: Point taken! I've changed it to "solution". -
for .. inis 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...inloop 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.
overslacked : As I mentioned in the question, this is a minimalist example that only reproduces the problem; but your point is a good one.overslacked : Just to make sure I'm giving proper credits, your answer was 100% accurate; but it was the initial information provided in Steve's answer regarding why the problem was occurring at all that I needed. Thanks for the help!
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.