Bug 14901

Summary: for in loop on an Array does not work
Product: WebKit Reporter: Andrea Trasatti <atrasatti>
Component: JavaScriptCoreAssignee: Nobody <webkit-unassigned>
Status: RESOLVED INVALID    
Severity: Normal CC: ap, mitz, wesc
Priority: P2    
Version: 419.x   
Hardware: Mac   
OS: OS X 10.4   
Attachments:
Description Flags
test (works for me)
none
test that does not work for me none

Description Andrea Trasatti 2007-08-08 02:53:52 PDT
I created a test Array with 3 elements, tried to cycle with a for in loop. Safari simply does not enter the loop.

This is a sample script I wrote:
var mycars=new Array();
mycars[0]='Saab';
mycars[1]='Volvo';
mycars[2]='BMW'; ".
for (i=0;i<mycars.length;i++) {
        alert('car maker id'+i+', name '+mycars[i]);
}
Comment 1 Andrea Trasatti 2007-08-08 03:07:27 PDT
(In reply to comment #0)
Obviously the submitted code sample was wrong.

What I wanted to submit as a sample is:
var mycars=new Array();
mycars[0]='Saab';
mycars[1]='Volvo';
mycars[2]='BMW';
for (var i in mycars) {
        alert('car maker id'+i+', name '+mycars[i]);
}


Comment 2 Alexey Proskuryakov 2007-08-08 06:29:36 PDT
Created attachment 15867 [details]
test (works for me)

Same test in an attachment.

Seems to work fine in shipping 10.4.10 Safari/WebKit, and also with nightly r24875.
Comment 3 Andrea Trasatti 2007-08-08 07:06:45 PDT
Created attachment 15868 [details]
test that does not work for me
Comment 4 Andrea Trasatti 2007-08-08 07:08:23 PDT
(In reply to comment #2)
> Created an attachment (id=15867) [edit]
> test (works for me)
> 
> Same test in an attachment.
> 
> Seems to work fine in shipping 10.4.10 Safari/WebKit, and also with nightly
> r24875.

It is working for me too, actually. Weird how I could not make it work in my page and then created a sample script that worked.

The original reason why I filed the bug was this:
var children = document.getElementsByTagName('SELECT');
alert(children.length);
for (var c in children) {
   alert('loop '+c);
}


I left the alerts just for your reference. In my page I have 5 select elements and the first alert correctly says so, but then never gets to the "loop*" alerts.
See the new attachment that I have created. I made two versions one that is within a function and one (less readable) directly in the select element.
Comment 5 mitz 2007-08-08 07:24:48 PDT
(In reply to comment #4)
> var children = document.getElementsByTagName('SELECT');
> alert(children.length);
> for (var c in children) {
>    alert('loop '+c);
> }

The result of getElementsByName is not an array, it is a NodeList. for-in enumerates properties of the NodeList object. To enumerate the nodes in the NodeList you can do something like
for (var i = 0; i < children.length; i++)
    alert('loop' + children[i]);
Comment 6 Andrea Trasatti 2007-08-08 08:04:40 PDT
(In reply to comment #5)
> (In reply to comment #4)
> > var children = document.getElementsByTagName('SELECT');
> > alert(children.length);
> > for (var c in children) {
> >    alert('loop '+c);
> > }
> 
> The result of getElementsByName is not an array, it is a NodeList. for-in
> enumerates properties of the NodeList object. To enumerate the nodes in the
> NodeList you can do something like
> for (var i = 0; i < children.length; i++)
>     alert('loop' + children[i]);
> 

True, nevertheless for-in works fine on MSIE7 and FF2. Isn't the NodeList enumerated? Why would for work and for-in not?
It seems to me like the suggested loop, which is actually the exact same thing I did to fix it with Safari, should behave the same way as a for-in, while the for-in has a more compact syntax and is more readable, in this case.
Comment 7 Wes Contreras 2008-09-17 12:44:27 PDT
I'm working with Chrome (beta) and having a similar issue with for/in and arrays. Here is my test script:

var myarray = [5,3,8,"test","nowork"];
for (var elem in myarray) {
  document.write("<br>" + elem);
}

Here is my output:

0
1
2
3
4

It appears to be outputting the array keys instead of the array values. The following code works perfectly, but for my solution, I can't count on contiguous  array elements, so this solution requires a lot more logic than a simple for/in loop.

for (var ii = 0; ii < myarray.length; ii++) {
  document.write("<br>" + myarray[ii]);
}
Comment 8 Alexey Proskuryakov 2008-09-18 01:54:23 PDT
(In reply to comment #6)
> True, nevertheless for-in works fine on MSIE7 and FF2. Isn't the NodeList
> enumerated? Why would for work and for-in not?

I think that this was a bug in WebKit shipping with Safari 2, fixed in Safari 3. However, it's still a bad idea to use for-in with NodeLists. For-in enumerates all properties of NodeList, so you get not only loop 0...loop 4, but also loop length and loop item. This is rarely what is needed.

(In reply to comment #7)
> 0
> 1
> 2
> 3
> 4

I'm getting identical results in Firefox.

Since this bug doesn't contain any issues identified as bugs, I'm closing it as INVALID. Please feel free to open new bugs if you disagree - this one contains a lot of confusion between arrays and NodeLists, so it would be better to avoid continuing the discussion here.