12 Replies Latest reply on Mar 31, 2009 9:49 AM by (Dave_Saunders)

    Using for ... in with arrays

    Level 1
      Is it obvious to everybody that:
      var myArray = [3,4,5]
      
      for (j in myArray) {
        $.writeln(j);
      }
      produces in the JavaScript Console:

      0
      1
      2
      Execution finished.

      I stumbled on a script yesterday that I wrote a while back that used this technique for iterating through an array but I had to step back and try this test to convince myself that it actually works.
        • 1. Re: Using for ... in with arrays
          Fred Goldman Level 3
          It makes sense, because an array is an object and the properties of the
          array are the index number of the array element.

          Try this:

          var myArray = new Array(50)
          myArray[25] = 3
          for (j in myArray) {
          $.writeln(j);
          }
          • 2. Re: Using for ... in with arrays
            Level 1
            Fred,

            Right. It was that realization that had it making sense for me, once I'd thought it through.

            I wonder which is quicker:

            for (var j in myArray)

            for (var j = 0; myArray.length > j; j++)

            I appreciate that these aren't necessarily equivalent, but every time I use the latter, I surely could have used the former.

            Dave
            • 3. Re: Using for ... in with arrays
              Level 1
              There is a difference between the two. In the second example below, i is a string, not an int. (put a debugger statement in there and do typeof( i ); in the console to prove it). In the second example we're asking for the array index of:
              "01", "11", "12"...

              And they're all undefined.

              I NEVER use the for( var i in array ) syntax for that reason. If you do introduce a bug there, it's one of those bugs that your eye doesn't catch, and takes forever to find.

              Bob

              var array = [0,1,2,3,4,5,6,7,8,9];

              for ( var i = 0; i < array.length - 1; i++ ) {
              $.writeln( array[ i + 1 ] );
              }

              for ( var i in array ) {
              $.writeln( array[ i + 1 ] );
              }
              • 4. Re: Using for ... in with arrays
                Fred Goldman Level 3
                But why doesn't something like this work?

                Isn't myDoc.characterStyles an array?

                myDoc = app.activeDocument;
                for (j in myDoc.characterStyles)
                alert(myDoc.characterStyles[j].name)
                • 5. Re: Using for ... in with arrays
                  Fred Goldman Level 3
                  You could do this:

                  for ( var i in array ) {
                  $.writeln( array[ Number(i) + 1 ] );
                  }
                  • 6. Re: Using for ... in with arrays
                    Level 1
                    Ah, thanks Bob.

                    Dave
                    • 7. Re: Using for ... in with arrays
                      Fred Goldman Level 3
                      It seems that myDoc.characterStyles is a regular object with a length
                      property added to it, not an actual array.

                      Another major difference between the for/in and traditional loops is
                      that the for/in loop will not loop through the full length of the array
                      if it has undefined items whereas the traditional for loop will.

                      For example:

                      myDoc = app.activeDocument;
                      myArray = new Array(myDoc.characterStyles.length)
                      myArray[3] = 4;
                      for (j in myArray)
                      $.writeln(j)

                      Will only loop once despite the fact that there may be more than one
                      character style in the document.
                      • 8. Re: Using for ... in with arrays
                        Level 1
                        Exactly, Fred. That's why I never use the var i in array syntax. There's just too many possibilities for subtle errors.

                        Bob
                        • 9. Re: Using for ... in with arrays
                          Level 1
                          > Isn't myDoc.characterStyles an array?

                          There are 'Collection' objects in Adobe/JS-land that look kinda like Arrays but
                          really aren't. It would have been very nice if they would have made these
                          collection objects proper subclasses of Array.
                          • 10. Re: Using for ... in with arrays
                            Fred Goldman Level 3
                            I see, so collections don't support the for/in loop as arrays do.

                            Is there anything else arrays support that collections don't?
                            • 11. Re: Using for ... in with arrays
                              Level 1
                              Because collections are objects, they do support for/in loops, but the results aren't very useful:
                              myDocs = app.documents;
                              
                              for (j in myDocs) {
                                 $.writeln(j);
                              }
                              produces:
                              length
                              
                              Execution finished.
                              Which indicates that a collection has just one (visible) property named length.

                              Dave
                              • 12. Re: Using for ... in with arrays
                                Level 1
                                xbytor wrote: "There are 'Collection' objects in Adobe/JS-land that look kinda like Arrays but really aren't. It would have been very nice if they would have made these collection objects proper subclasses of Array."

                                That won't work for all of the languages we support. In VBScript, for example, these collections give us capabilities that we would not otherwise have (ItemByName, ItemByRange, etc.). While we could extend Array in JavaScript, we can't do that in the other languages (or, at least, we can't do so given our current process). There are a lot of things that our collections support that arrays don't (except in AppleScript, where arrays and collections work about the same way--in fact, our collections are based on the AppleScript model).

                                Our "one size fits all" approach does sometimes mean that we can't take advantage of all of the features of a specific language, but it's better than the alternatives--hand coding for each language you want to support (look at some of the other CS applications, which have different DOMs for differing languages), or limiting scripting to a single language.

                                This is also why I always use the collection.item(index) form when working with these collections and the array[index] form for arrays. This reminder makes it much easier for me when I'm updating scripts.

                                Thanks,

                                Ole