-1

To the code:

<!DOCTYPE html>
<html>
<body>
<p>This.........</p>
<p>That.....</p>
<p>And yet .....</p>
<script>
x=document.getElementsByTagName("p");
for (i in x)  
    document.write("..."+x[i].innerHTML+" "+i+"<br>");
document.write(x.length);
</script>
</body>
</html>

i'm getting the output

This.........

That.....

And yet .....
...This......... 0
...That..... 1
...And yet ..... 2
...undefined item
...undefined namedItem
...undefined iterator
...undefined length
3

rather than the following which is what i expect:

This.........

That.....

And yet .....
...This......... 0
...That..... 1
...And yet ..... 2
3

the for-in statement is supposed to iterate on x as many times as the length of x-- which is 3 as the code itself is saying-- and terminate. what it seems to be doing instead is iterating on all the children of the node-- not just the paragraph tags returned by document.getElementsByTagName("p").

this is either some subtlety i'm missing in the code, or a mistake in the JavaScript engine.

What's missing here?

20
  • 1
    You need a regular for loop. Commented Oct 30, 2013 at 23:27
  • 4
    Short answer: do not use for..in for iterating arrays or sequences. for..in iterates properties (which includes array indexes, but also other properties like item and iterator). Commented Oct 30, 2013 at 23:27
  • 6
    "or a mistake in the JavaScript engine" --- it's 99.9999% chance that every error you experience in next year of your career is your mistake, not ECMAScript implementation's Commented Oct 30, 2013 at 23:27
  • 2
    the for-in statement is supposed to iterate on x as many times as the length of x - Wrong. That is not what the for ... in statement means at all. It iterates over the keys of x. Commented Oct 30, 2013 at 23:28
  • 1
    @ashley it's part of the core language, but it doesn't do what you think it does :) Commented Oct 30, 2013 at 23:33

2 Answers 2

7

Don't use for ... in for arrays and array-like things like NodeList objects. Always use a numeric index.

The for ... in construct is for iterating through the enumerable properties of an object. Strictly speaking, it doesn't even guarantee that the numeric properties will be traversed in numeric order! Use a numeric index, or else convert array-like objects to real arrays and use .forEach() (in newer browsers):

var x = document.getElementsByTagName("p");
[].slice.call(x, 0).forEach(function(value, index) {
  document.write("..." + value.innerHTML + " " + index + "<br>");
});

edit — RobG points out correctly that the .slice() trick won't work in IE versions before IE9. It's easy enough to do the same thing with a simple for loop with a numeric index, so if you're worried about IE8 or below, just do that:

var x = document.getElementsByTagName("p");
for (var i = 0; i < x.length; ++i) {
  // whatever with x[i]
}

Really old versions of Mozilla, I think, didn't even support using array indexing with Node objects; you had to use the .item( i ) method. I don't think that's a serious concern for realistic new code however.

Sign up to request clarification or add additional context in comments.

7 Comments

@RobG ha ha yes thanks, I just fixed that. I don't think using "slice" on a NodeList has any bad repercussions; the MDN documentation includes similar suggestions in examples.
MDN is a community wiki for Mozilla browsers, I'm sure at least some of the authors are happy to publish code that will fail in IE. ;-)
@RobG well IE9+ can do it. I'm starting to live in the fantasy dream world of not worrying about Windows XP anymore.
—yes, IE9 finally starts to behave like a real browser but unfortunately (depending on whose stats you believe) IE8 is still used by about 12% to 15% of web users.
@Pointy: personally, I'll stop supporting IE8 when XP extended support ends - the vast majority of the IE8 users are on XP, and end users really should know better.
|
1
var x=document.getElementsByTagName("p");
for(var i=0;i<x.length;i++)
{
  document.write("..."+x[i].innerHTML+" "+i+"<br>");
}

1 Comment

yes, so the ; after i++ made an error, sorry. just edited.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.