20 Replies Latest reply on Mar 22, 2011 4:44 AM by Peter Kahrel

    JS: display object

    Peter Kahrel Adobe Community Professional & MVP

      It looked so easy: display a (JSON-type) object so that its hierarchy is visible -- but I can't get it to work properly. I'll explain in a separate message.

       

      Peter

        • 1. Re: JS: display object
          Peter Kahrel Adobe Community Professional & MVP

          Take this object and script:

           

          obj = {
                   mammals:
                      {
                      cats:["tabby", "manx"],
                      dogs:["terriers", {colly:["border", "highland"]}, "labrador", {spaniel:["long", "short"]}, "alsatian"]
                      },
                   insects:["ants", "bees", "spiders"]
                   }


          DisplayObject (obj, "");

          function DisplayObject (obj, indent)
             {
             for (var i in obj)
                if (obj[i] instanceof Object)
                   {
                   $.writeln (indent+i+"@");
                   DisplayObject (obj[i], indent+=">");
                   }
                else
                   $.writeln (indent+obj[i]+"£");
             }

           

          The DisplayObject function is just a bog-standard recursive thing that traverses an object (I added the @ and £ symbols so I could check that terminals and non-terminals are printed correctly). I had expected this output:

           

          mammals@
          >cats@
          >>tabby£
          >>manx£
          >>dogs@
          >>>terriers£
          >>>colly@
          >>>>border£
          >>>>highland£
          >>>labrador£
          >>>spaniel@
          >>>>long£
          >>>>short£

          >>>alsatian£
          insects@
          >ants£
          >bees£
          >spiders£

           

          But instead I get this:

           

          mammals@
          >cats@
          >>tabby£
          >>manx£
          >>dogs@
          >>>terriers£
          >>>1@
          >>>>colly@
          >>>>>border£
          >>>>>highland£
          >>>>labrador£
          >>>>3@
          >>>>>spaniel@
          >>>>>>long£
          >>>>>>short£
          >>>>>alsatian£
          >insects@
          >>ants£
          >>bees£
          >>spiders£

           

          Each time an embedded object is encountered, the script inserts a number (which looks as if it's the object's position in the array) and adds a level. I'm at a loss to see what's happening. Anybody know what's happening here?

           

          Thanks,

           

          Peter

          • 2. Re: JS: display object
            [Jongware] Most Valuable Participant

            Don't know about the numbers, but the list should be a *little* better when you replace this line

             

            DisplayObject (obj[i], indent+=">");

            with this

             

            DisplayObject (obj[i], indent+">");

            (It removes the extra indent level.)

            • 3. Re: JS: display object
              Peter Kahrel Adobe Community Professional & MVP

              Indeed it does, thanks. Those numbers still print, though.

               

              Peter

              • 4. Re: JS: display object
                Mayhem SWE Level 2

                As far as I can tell your script is doing exactly what you tell it to do. You are treating Arrays and Objects as if they were the same thing. When iterating over an Object your code will write out the label for the current property, when iterating over an Array it will write out the index of the current item.

                • 5. Re: JS: display object
                  John Hawkinson Level 5

                  You might want to look at json2.js for tips on recursive descent of JavaScript objects.

                   

                  Your numbers are array index positions that contain Objects.

                  if (obj[i] instanceof Object)
                           {
                           $.writeln (indent+i+"@");
                  

                   

                  so for each case where obj[i] is an Object, you print the index into obj before you descend into it.

                   

                  I feel like you will trip of because you don't test .hasOwnProperty but that seems to be untrue in the genreal case.

                  • 6. Re: JS: display object
                    Peter Kahrel Adobe Community Professional & MVP

                    Thanks for both your responses.

                     

                    Mayhem --

                     

                    >You are treating Arrays and Objects as if they were the same thing.

                     

                    It looks like that, yet object keys are printed in first $.writeln() (suffixed with @), array elements in the second one (suffixed with £). "1" and "3" are printed in the first line and appear to be interpreted as keys. Why would an (embedded) object's array index be interpreted as a key?

                     

                    >when iterating over an Array it will write out the index of the current item.

                     

                    Well, it doesn't do that when it writes array elements such as "tabby", "ant", etc.

                     

                    But I see your point that obj[i] instanceof Object appears not to distinguish between arrays and other objects, but the script's output suggets otherwise.

                     

                    John --

                     

                    Thanks for the link to json2.js, I'll look into that.

                     

                    Peter

                    • 7. Re: JS: display object
                      John Hawkinson Level 5

                      > Why would an  (embedded) object's array index be interpreted as a key?

                       

                      Why wouldn't it? An Array is a subclass of an Object. Indices into the array are keys to it as well.

                       

                      > the script's output suggets otherwise.

                       

                      I think you're getting confused by the recursion. Your function prints the index and then calls itself after dereferencing the index, so every time it finds an a new Object it prints its index and then its contents. Since you have only two objects (inside your outer initial object), this happens only twice.

                      • 8. Re: JS: display object
                        Peter Kahrel Adobe Community Professional & MVP

                        Thanks. I still don't get it, but I'll have a think and see if I can get it to work.

                         

                        Peter

                        • 9. Re: JS: display object
                          Mayhem SWE Level 2

                          Why would an (embedded) object's array index be interpreted as a key?

                          Because your script is written that way?

                           

                          Imagine putting a much simpler test case through your function.

                           

                          ["item_0", {"item_1": ["item_1.0", "item_1.1"]}]
                          

                           

                          Your script will begin to iterate over the outermost object. Since this is an array, it will start by examining index 0, determine that "Item_0" is not an instance of object, and thus write out only the value of the item.

                           

                          It will then move onto index 1. Since the contents at index 1 is indeed an instance of object, your script will write out the value of variable i which obviously is 1, then recursively process the contents at index 1.

                           

                          Now we're entering another loop. Since we are now processing an object, we will iterate over that object's keys. It has only one key and that is "item_1". The loop will examine the value for key "item_1", determine that it is an instance of object, and thus print out the value of variable i (which is "item_1") followed by recursively processing the value at key "item_1".

                           

                          Now we're entering yet another loop. This time we're processing an array, so we will start by examining index 0. Index 0 contains a string, which is not an instance of object, so we write out the value at index 0, which is "item_1.0". Move on to index 1, which contains a string, write it out, "item_1.1".

                           

                          No more items to process, go back up a level, rinse and repeat...

                          • 10. Re: JS: display object
                            Peter Kahrel Adobe Community Professional & MVP

                            Thanks very much for your explanation.

                             

                            >Because your script is written that way?

                             

                            Quite. But clearly I don't understand something very basic.

                             

                            >variable i which obviously is 1

                             

                            This is not obvious for me at all. The value of the first array element is the string "item_1" -- that's clear. What is not clear to me is why the value of the second item is its index. From the way that the output is produced it almost looks as if the second array element (the object) is really embedded under its index, as follows.

                            ["item_0", {1:{"item_1": ["item_1.0", "item_1.1"]}}]

                             

                             

                            Thanks,

                             

                            Peter

                            • 11. Re: JS: display object
                              John Hawkinson Level 5

                              Peter, you're confusing i and obj[i]. The value of all indices of an array are the integer indices, 1,2,3,etc. But your function only prints the index if the type of the item is an Object!

                              • 12. Re: JS: display object
                                Mayhem SWE Level 2

                                This is not obvious for me at all. The value of the first array element is the string "item_1" -- that's clear. What is not clear to me is why the value of the second item is its index. From the way that the output is produced it almost looks as if the second array element (the object) is really embedded under its index, as follows.

                                ["item_0", {1:{"item_1": ["item_1.0", "item_1.1"]}}]

                                No. You are somehow expecting your nested data to behave something like

                                {"item_0", "item_1":["item_1.0", "item_1.1"]}

                                which of course isn't legal JavaScript as you cannot mix-and-match unlabeled and labeled items. In order to achieve your expected behaviour without changing the processing code, data input would have to be formatted something like

                                {0:"item_0", "item_1":["item_1.0", "item_1.1"]}

                                or perhaps

                                {"item_0":[], "item_1":["item_1.0", "item_1.1"]}

                                 

                                You may be confused now, but when you get it it'll seem so obvious!

                                • 13. Re: JS: display object
                                  Peter Kahrel Adobe Community Professional & MVP

                                  >you're confusing i and obj[i].
                                  >You may be confused now,

                                   

                                  I am!

                                   

                                  >but when you get it it'll seem so obvious!

                                   

                                  Look forward to it.

                                   

                                  Peter

                                  • 14. Re: JS: display object
                                    John Hawkinson Level 5

                                    Here, Peter. Just move your printing of the index out of the if. Now you get the index ALL the time, not just on array items that happen to be objects:

                                     

                                    function DisplayObject (obj, indent) {
                                       for (var i in obj) {
                                            $.writeln (indent+i+"@");
                                            if (obj[i] instanceof Object) {
                                                DisplayObject (obj[i], indent+=">");
                                            } else {
                                                $.writeln (indent+obj[i]+"£");
                                            }
                                        }
                                    }
                                    
                                    • 15. Re: JS: display object
                                      Peter Kahrel Adobe Community Professional & MVP

                                      Thanks very much. Don't want to appear ungrateful, but I'd rather have it without any of the index. Anyway, this one will keep me out of mischief for a bit.

                                       

                                      Peter

                                      • 16. Re: JS: display object
                                        John Hawkinson Level 5

                                        Well, the goal was so you understood why it was happening!

                                        You'll need to treat Arrays and Objects differently if you want to fix this.

                                        • 17. Re: JS: display object
                                          Marc Autret Level 4

                                          Hi Peter,

                                           

                                          Just to complete the above comments, keep in mind that Array indexes actually are enumerable property names although the JS specification gives special meaning and treatment to it:

                                           

                                          ( From ECMA-262 — 15.4 Array Objects )

                                           

                                          Array objects give special treatment to a certain class of property names. A property name P (in the form of a String value) is an array index if and only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal to 2^(32−1). A property whose property name is an array index is also called an element. Every Array object has a length property whose value is always a nonnegative integer less than 2^32.

                                           

                                          Hence the syntax:

                                           

                                          myItems = ["item0", "item1", "item2"];
                                          

                                           

                                          is *quite* similar to the following:

                                           

                                          myItems = {
                                               "0": "item0",
                                               "1": "item1",
                                               "2": "item2",
                                               };
                                          myItems.__proto__ = Array.prototype;
                                          

                                           

                                          Of course the 2nd form produces a fake Array but it behaves the same way in most respect. Note that "0", "1", etc., are enumerable property names (i.e. 'keys') in both the Array and the fake Array. Note also that myItems[0]===myItems["0"], myItems[1]===myItems["1"], etc.

                                           

                                          @+

                                          Marc

                                          • 18. Re: JS: display object
                                            [Jongware] Most Valuable Participant

                                            That actually makes sense to me, as I always thought that enumerated objects were some kind of very special Array -- different enough for me to not understand how it worked. Seeing "perfectly normal arrays" as objects with a name "0", "1", "2" (etc.) makes me realize it's the other way around!

                                             

                                            (Mind you, I come with a lot of luggage from Basic and C, where what seems to be perfectly normal arrays are, in reality, perfectly normal arrays )

                                            • 19. Re: JS: display object
                                              Mayhem SWE Level 2

                                              Peter, look at the paths to the various branches within your object obj defined in the second post of this topic. How would you reach the value labrador? I hope we can both agree on this:

                                               

                                              obj["mammals"]["dogs"][2] == "labrador"; // true

                                               

                                              Now how would you reach value highland? Here is where it gets tricky. Based on the output you're expecting from your recursive algorithm, you seem to believe this would be correct:

                                               

                                              obj["mammals"]["dogs"]["colly"][1] == "highland"; // error!

                                               

                                              It will however throw an error. The hierarchy is Object -> Object -> Array -> Object -> Array -> String, so the correct path must be:

                                               

                                              obj["mammals"]["dogs"][1]["colly"][1] == "highland"; // true

                                               

                                              Your script walks the exact same path. Every time your loop encounters an instance of Object (which includes Array) you're asking it to write out it's current location (your variable i), which depending on what we are iterating over might be the property key of a value in an object or the index of an item in an array, before going one level deeper by recursion. Examine your code. Examine your data. Be enlightened!

                                               

                                              (By the way, this forum software is truly awful. I had to edit this message several times before the formatting saved correctly...)

                                              • 20. Re: JS: display object
                                                Peter Kahrel Adobe Community Professional & MVP

                                                Marc, Mayhem,

                                                 

                                                Like Jongware, I assumed that arrays were just arrays (as they are in Basic and Pascal). I know that objects can be represented as associative arrays, and I must admit that I never realised that what I considered normal arrays aren't all that normal after all.

                                                 

                                                Thanks both of you: those last two examples and their clear explanation finally made things clear to me (I think).

                                                 

                                                >Be enlightened!

                                                 

                                                I am in great danger of becoming just that! It's been an educational thread for me.

                                                 

                                                >this forum software is truly awful.

                                                 

                                                It's a complete and utter disgrace.

                                                 

                                                Peter