2

I'm developing a tool to create Nassi-Shneiderman diagrams online. The model for each diagram is simply an object literal, storing everything with unlimited possible children.

this then results in a view populated like the following: View

Now if I want to add let's say a sequence into the while loop after the first sequence, I somehow have to add a child to the object between the two existing children. The order of an object's properties is not editable by default though and W3C says that one should not rely on the order of the properties because the can differentiate between browsers. I know I could store the object's order in an array, but then I'd have to rewrite the recursive loop which populates the view and so on..

Can I somehow manipulate the order of an object's properties? I don't mind using 3rd party libraries.

By "order" I mean the order an object's properties get iterated over using a for(prop in obj) loop.

Here's an example of my data structure/object:

{
    "procedure": {
        "id": "content",
        "child": {
            "154": {
                "class": "sequence",
                "text": "json manually created in code",
                "id": 154,
                "contenteditable": "true"
            },
            "155": {
                "class": "while",
                "id": 155,
                "child": {
                    "157": {
                        "class": "while-condition",
                        "text": "while JSON from File imported",
                        "id": 157,
                        "contenteditable": "true"
                    },
                    "158": {
                        "class": "while-body",
                        "id": 158,
                        "child": {
                            "159": {
                                "class": "sequence",
                                "text": "Sequence in a while loop",
                                "id": 159,
                                "contenteditable": "true"
                            },
                            "160": {
                                "class": "while",
                                "id": 160,
                                "child": {
                                    "161": {
                                        "class": "while-condition",
                                        "text": "while parentNode.Whatever != FALSE",
                                        "id": 161,
                                        "contenteditable": "true"
                                    },
                                    "162": {
                                        "class": "while-body",
                                        "id": 162,
                                        "child": {
                                            "163": {
                                                "class": "sequence",
                                                "text": "Sequence even deeper nested",
                                                "id": "163",
                                                "contenteditable": "true"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            },
            "156": {
                "class": "sequence",
                "text": "Finish Procedure",
                "id": 156,
                "contenteditable": "true"
            }
        }
    }
}
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
philx_x
  • 1,708
  • 16
  • 23
  • If you want order, you want an array. Period. Properties on an object do not have an order to them. The order is not guaranteed and, in fact, there is no method to insert one property before another (because there is no order to them). – jfriend00 Mar 13 '15 at 07:57
  • FYI, ECMAScript 2015 changes things; I've updated my answer. – T.J. Crowder Aug 06 '15 at 17:52

1 Answers1

2

(ECMAScript 2015 ("ES6") changes things: See update at end of answer.)

Object properties have no order (neither in JavaScript nor in JSON). (More below.) To have order, you must use an array, not object properties. You'll have to adjust your structure to have children: [] rather than child: {}. Then, of course, adding an entry between two of them is a matter of using splice (spec | MDN).

About object property order and the lack thereof:

JSON

From the JSON website:

An object is an unordered set of name/value pairs.

(My emphasis)

JavaScript

In JavaScript, the order in which properties are visited by a for-in loop is not specified — see §12.6.4 of the spec:

The mechanics and order of enumerating the properties (step 6.a in the first algorithm, step 7.a in the second) is not specified.

(My emphasis)

Therefore each JavaScript engine can do whatever it wants. It might visit them in the order they were added to the object (a number of engines seem to do that). Or in alphabetic order. Or in order according to whatever is most convenient for their property storage mechanism, which very well may be a hash tree, and therefore seemingly-random if you don't know the hashing mechanism.

Similarly, Object.keys has no guaranteed order, all the spec says is that if an engine guarantees an order for for-in, then Object.keys must follow that order. But as the spec doesn't require engines to guarantee an order...


As of ECMAScript 2015 (ES6), object properties have order now:

  1. Let keys be a new empty List.
  2. For each own property key P of O that is an integer index, in ascending numeric index order
    • Add P as the last element of keys.
  3. For each own property key P of O that is a String but is not an integer index, in property creation order
    • Add P as the last element of keys.
  4. For each own property key P of O that is a Symbol, in property creation order
    • Add P as the last element of keys.
  5. Return keys.

...so you could indeed do this by manipulating the order in which the properties were added to the object. I'm not suggesting you do it, but it's possible now, on compliant engines.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • i'd say they do have a certain order even if not explicitly defined. how else would it result in the same every time i iterate over an objects properties with a loop. for (var key in obj). nice approach with the child array, didn't think of that, i'll definetly give it a try. thanks – philx_x Mar 13 '15 at 08:00
  • 2
    @philx_x - a given object property implementation likely has some sort of order, but it is not specified in any specification and is not controllable - and could even change as other properties are added (as could happen with a hash table) and could certainly vary from one browser implementation to another - thus there is no guaranteed order. Besides good cross browser programming practice relies only on features that are specified in a specification and uniformly implemented, not on implementation specific behaviors with no specification. – jfriend00 Mar 13 '15 at 08:07
  • 1
    @philx_x: There is no order guarantee, at all. There is no guarantee of visiting the properties in any particular order, nor is there a guarantee that if you loop twice, you'll loop through them in the same order. Different engines are free to do anything they want in this regard. In practice, most engines loop properties in the order in which they were added to the object, but that is **not** guaranteed, nor can you do anything to change the order. (You could try by creating a new object and adding properties to it in the order you want, but you'd be relying on undocumented behavior.) – T.J. Crowder Mar 13 '15 at 08:07