Universal getter for plain JS objects.

Many times in JavaScript we have to reach deep into objects to access fields that could possibly not be there at all; for example let’s assume I have a JS object called options into which I’ve just read an entire JSON configuration file. Trying to access a field like options.application.cache.enable directly will potentially fail (e.g. when any of the intermediate levels is missing)…

if (options.application.cache.enable) {
    // do stuff
}

…therefore this kind of work will usually involve some kind of testing for the existence of each level, so as to gracefully handle any misbehaving data. Also, many times I’ve seen the following approach used in these scenarios which is quite bad for anything more than a single depth level:

if (options && options.application && ...) {
    // do stuff
}

So, just as a little helper, here is a small method that may prove to be quite handy when having to deal with data whose structure we’re not certain of (here’s a proper Gist entry).

/**
 * Universal field getter method for JavaScript objects.
 * @param  {String} _path    The field path inside `this`.
 * @param  {...}    _default The default value to be returns if field is not found.
 * @return {...}             Returns the found field value else `_default` else `undefined`.
 */
Object.prototype._ = function(_path, _default) {
    var value = _path.split('.').reduce(
            function(hash, field) {
                return hash && hash[field]
            },
            this
        );
    return typeof(value) === 'undefined' ? _default : value;
}

It’s simple and short enough to carry around in your kung-fu belt. I also think you’re smart enough to understand what it does. And here is how this would work:

// let's access what we wanted from the options object
var result = options._('application.cache.enable');

// this returns `true` (i.e. a default value) when the field is missing
var result = options._('application.cache.enable', true);

// this uses a brand new object (just for kicks)
{}._('a.b.c.d'); // undefined
{}._('a.b.c.d', 148); // 148 

// it even works with arrays
var obj = {
    items: [
        {
            label: "awesome"
        }
    ]
};
obj._('items.0.label'); // awesome

That’s pretty much it.

Note:

I know! It’s implemented as an Object method despite all warnings, get over it. This is because it seems to me that this functionality is generic enough to be applied to any Object (if you disagree, just make it a standalone function and be happy about it).

Enjoy!

Comments are closed.