2

My Query:

What is the most efficient way to reference nested JavaScript objects? I have found a couple so far, and am wondering which is the most efficient, and if there are any others which are better than those which I list here. The problem involves usage of a root object, similarly to that which many JavaScript frameworks use. The root object is compulsory. Please do not post answers which do not use a root object.

Note that this is specifically intended for root/sub-root objects which have long names - referencing a.b would be useless, whilst referencing abcdefghijklm.nopqrstuvwxyz would be extremely useful.

EDIT:

Just to clarify a couple of things:

  • Via efficiency I mean firstly code length (which could in turn affect performance, but that is slightly less important). I am concerned about code length partially because of file size - yes, I would be minifying it afterwards - but also due to readability for anyone viewing my original code (including myself). Performance is also slightly important, I don't want long workarounds which would slow down execution.
  • The referencing would be mostly for commonly used sub-objects, NOT EVERY SINGLE ONE. I state (in method 1) that many global variables would need to be created - due to the fact that I was assuming that all of the first-level sub-objects would be commonly used.

Objects to be referenced:

The object foo contains the various sub-objects bar, baz and qux, each of which contain various other objects.

var foo = {

    bar: {

        bar: {},
        baz: {},
        qux: {}

    },
    baz: {

        bar: {},
        baz: {},
        qux: {}

    },
    qux: {

        bar: {},
        baz: {},
        qux: {}

    }

};

Method 1 - Reference Variables:

The first method involves creating a variable for each of the sub-objects.

var bar = foo.bar;
var baz = foo.baz;
var qux = foo.quz;

foo.bar.baz could then be referenced simply via bar.baz, and foo.qux.qux via qux.qux.

Advantages:

  • Reference variables can be very concise - a single character is the minimum possible length.

Disadvantages:

  • If there are many sub-objects to be referenced, this would increase the global variable count. This is likely to cause conflicts, cross-script and otherwise - especially using single-character variable names.
  • A new reference variable needs to be created for every nested object. Not only is this inconvenient, but it also requires the programmer to remember to create each variable after amending the object. Conversely, if a sub-object is removed and the programmer forgets to remove the reference variable also, then the code becomes messy with useless global variables cluttering it up.

Method 2 - Reference Function:

The second method involves creating a function which returns a sub-object, depending on a couple of parameters.

function ref(a, b) {

    //Ensure that the first parameter is passed:
    if (!a) {

        return false;

    }

    return foo.a.b;

};

foo.bar.baz could then be referenced via ref("bar", "baz"), and foo.qux,qux via ref("qux", "qux").

Advantages:

  • Works for all first-level sub-objects, without repetitive and messy separate variable defining.

Disadvantages:

  • Only really useful for shortening the root object - if the root object is named a then using the reference function would actually lengthen the code.
Ædx
  • 84
  • 1
  • 11
  • Perhaps a question for codereview rather than SO? – Johan Oct 18 '14 at 20:25
  • Please quit the foo/bar examples, they make quite no sense. Are you looking for a way to shortcut property names, and have, for instance, ‘myRect.aw‘ exactly refer to ‘myRect.actualWidth‘ (either when writing or reading) ?? I could explain how so if you wish. – GameAlchemist Oct 18 '14 at 20:26
  • 1
    I don't get the point... Is this about tree structures? What's the question again? – cschuff Oct 18 '14 at 20:32
  • 1
    I think, like @cschuff, that you should clarify the question and example. I wonder if the solution you might found will have any clear advantage over just caching the right object when you'll use it several times locally. (var rect = myGraphObj.rectangle; var width=rect.width; ...). But in fact if your issue is mainly about typing long (sub)property names, the real solution is to use an editor that will autocomplete for you... – GameAlchemist Oct 18 '14 at 21:03
  • Please define "efficient". In terms of what? Performance? Code length? – lexicore Oct 18 '14 at 22:30
  • @GameAlchemist, I was using the metasyntactic examples to generalise my question, thus making it applicable to more people who would search for it. SO SEO, if you like. – Ædx Oct 19 '14 at 08:58
  • @cschuff, this is not about tree structures. It is about referencing commonly used sub-objects in order to shorten code using them. – Ædx Oct 19 '14 at 09:00
  • @lexicore - code length is my most important factor, although performance would be appreciated. – Ædx Oct 19 '14 at 09:02
  • Does this answer your question? [Convert a JavaScript string in dot notation into an object reference](https://stackoverflow.com/questions/6393943/convert-a-javascript-string-in-dot-notation-into-an-object-reference) – dank8 Oct 09 '22 at 12:58

2 Answers2

2

Let's say we have a graphic control object, that is an instance of a GraphicObject Class (function).
Let's say one instance looks like :

grControl = {
   visual : {
     boundingBox : { x : , y : , width: , height : ... },
     ...
   },
   action : {
     ...
   }
};

The right way to create shortcuts is either :
• to cache locally the appropriate object in a var in a function that will use it :

function drawBBox (someGraphicControl) {
     var bbox = someGraphicControl.visual.boundingBox;
     // maybe you want also to cache sub-properties :
     var width = bbox.width;
     ...
}

• to define, on the prototype, a getter and/or a setter that will provide an access to the nested property :

// read-only example
Object.defineProperty(GraphicControl.prototype, 'width', 
                                { get : function() { 
                                           return this.visual.boundingBox.width }, 
                                  enumerable : true};


// read-write example
Object.defineProperty(GraphicControl.prototype, 'width', 
                                { get : function() { 
                                           return this.visual.boundingBox.width }, 
                                  set : function(val) {
                                           this.visual.boundingBox.width = val ; }, 
                                  },
                                  enumerable : true};

this way you can use :

 grObject.width  

and exactly refer to :

 grObject.visual.boundingBox.width
GameAlchemist
  • 18,995
  • 7
  • 36
  • 59
1

The usual practice in javascript depends upon the circumstances:

1) One-time access to that object in a particular function. If you're just making a one time access to a deeply nested reference, you just spell out the reference with all the intervening names:

var data = foo.baz.quz.prop1;

2) Multiple-accesses to a particular nested object. If there are multiple references to a particular deeply nested object, then you create a temporary local variable that points to the common object and then reference from that within the local function.

function getDeepData() {
    var obj = foo.baz.quz;
    var prop1 = obj.prop1;
    var prop2 = obj.prop2;
    var prop2 = obj.prop3;

    // code that uses prop1, prop2 and prop3 here

}

3) Iterating properties who's names are not known in advance. Since you don't know the property names in advance, this is done by iterating one level at a time (sometimes recursively) and just keeping the parent object in a local variable.


If you find yourself making lots of deeply nested one-time references all over your code, then you probably want to revisit the structure of your code or data because that can usually be avoided.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Excellent answer here. You have listed everything that I need, and then some. I think that I would find circumstance 2 the most useful currently, but will probably come back to this at other points. Thank you! – Ædx Oct 19 '14 at 09:17