2

In using Javascript with nested objects and I am constantly doing stuff like

const configDoc = Config && Config.Settings && Config.Settings.Group && 
    Config.Settings.Group.theThingIReallyWanted

Is there a shorthand for getting that nested reference?

JoshJoe
  • 1,482
  • 2
  • 17
  • 35
  • Not as part of the language, no. *edit* unless there's some new-syntax trick I'm forgetting about. – Pointy May 04 '17 at 15:40
  • Not really, however, it's not that hard to write – Icepickle May 04 '17 at 15:40
  • Do you want it to return `undefined` if anyone of those properties don't exist? Because that's what you'll get. I like returning empty objects when possible, like this: `return (((Config || {}).Settings || {}).Group || {}).theThingIReallyWanted || {});` – Chris May 04 '17 at 15:41
  • @lcepickle I realize it might not seem like much, but I've done this enough times and forgotten to do it enough times that I'm now looking for a shorthand way. – JoshJoe May 04 '17 at 15:43
  • @Chris yes, I do. – JoshJoe May 04 '17 at 15:44
  • Then maybe you could think about a way to restructure your code so you don't need to 'overcomplicate' the statements, potentially using defaults and just sending the parameters you actually need to a function that needs it? I cannot really estimate if from your code, but it seems the return statement is not the place where you should check if these things existed? – Icepickle May 04 '17 at 16:01
  • @Icepickle I used a simplified example, but I am actually using this to return a reactive variable in Meteor. So I need to return something that might later change to something else. Even if I wasn't using return in the example I'd still want to know the answer here. Thanks – JoshJoe May 04 '17 at 16:06
  • @Icepickle also, I've changed the example, removing the return since it isn't relevant to the question. Thanks – JoshJoe May 04 '17 at 16:08

5 Answers5

1

afaik there is no shorthand but you could use try catch to avoid chaining conditions...

var test = { a: '', b: { c: {} } }

try {
  return test.b.c;
} catch (e) {
  return undefined;
}

Cheerio :)

MarcelD
  • 393
  • 1
  • 9
  • Maybe I just need to write a function that does this and then when I want to do it, just pass the reference as a variable. – JoshJoe May 04 '17 at 15:45
  • a function which does a try catch for u? if its worth to save 2-3 lines of code - why not BUT maybe u want to return different things if u run into catch-block in different functions - so up to you ;) – MarcelD May 04 '17 at 15:50
1

You can go all out and add an extension to all objects. I know people tend to frown on using the Object prototype for extended object functionality, but I don't find anything easier than doing this. Plus, it's now allowed for with the Object.defineProperty method.

Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
    var obj = this;
    var needles = needle.split( "." );
    for( var i = 0; i<needles.length; i++ ) {
        if( !obj.hasOwnProperty(needles[i])) {
            return false;
        }
        obj = obj[needles[i]];
    }
    return true;
}});

Now, in order to test for any property in any object you can simply do:

if( obj.has("some.deep.nested.object.somewhere") )

Here's a jsfiddle to test it out, and in particular it includes some jQuery that breaks if you modify the Object.prototype directly because of the property becoming enumerable. This should work fine with 3rd party libraries.

Brian Sidebotham
  • 1,706
  • 11
  • 15
  • 2
    I like what you did here. To be honest I was hoping for some new ES6 ES7 shorthand that would do this. I'm not keen on the idea of using the prototype, but that is probably just my natural inclination. – JoshJoe May 04 '17 at 15:51
1

Sadly, there is no shorthand for safe access of nested properties in javascript. However some functional libraries provides helper functions for your problem (besides other useful stuff). Example (lodash):

return _.get(Config, 'Settings.Group.theThingIReallyWanted');
madox2
  • 49,493
  • 17
  • 99
  • 99
  • I am going to use this answer. Lodash also lets you import just the module you need. https://www.npmjs.com/package/lodash.get – JoshJoe May 04 '17 at 16:32
1

You coould iterate the given keys and return either the value or an object as default. later return the last property.

function getValue(o, path) {
    return path.reduce(function (o, k) {
        return (o || {})[k];
    }, o);
}

var o = {  Config: { Settings: { Group: { theThingIReallyWanted: 42 } } } };

console.log(getValue(o, ['Config', 'Settings', 'Group', 'theThingIReallyWanted'])); // 42
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

Using a try catch block could help:

try {
    return Config.Settings.Group.theThingIReallyWanted;
} catch(e) {
    // something is undefined
}

There is no easy way to recursively check if some value is defined.

nicovank
  • 3,157
  • 1
  • 21
  • 42