0

When accessing value of a nested JSON object key, we need to check for existence of parent keys to prevent undefined key errors.

Given this:

var obj = {
  aaa: {
    bbb: {
      ccc: {
        ddd: 'ok'
      }
    }
  }
};

// #1 cause error if any of the parent key is not defined (e.g. aaa, bbb, ccc)
const ddd = obj.aaa.bbb.ccc.ddd || 'none';

// #2 this works but lots of repetition
const ddd = obj.aaa && obj.aaa.bbb && obj.aaa.bbb.ccc && obj.aaa.bbb.ccc.ddd || 'none';

In the example above, #1 will not work if aaa, bbb, or ccc is not defined.

#2 works but you see the repetition of ancestor keys.

Q: Is there a JavaScript/ES6 syntax to simplify this or we need to write/use a custom function?

kctang
  • 10,894
  • 8
  • 44
  • 63
  • [There's no such thing as a "JSON Object"](http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/) – adeneo Mar 02 '16 at 01:07
  • https://en.wikipedia.org/wiki/Autovivification – apsillers Mar 02 '16 at 01:14
  • 2
    You could implement something clever with ES6 Proxies, but otherwise there's nothing new in ES6 and you should use the existing solution – Bergi Mar 02 '16 at 01:19
  • 1
    I don't think this is truly a duplicate. Too bad I can't post an answer. Destructuring with defaults helps a bit, though the syntax takes some getting used to: `const { aaa: { bbb: { ccc: { ddd = 'none' } = {} } = {} } = {} }`; – Jacob Mar 02 '16 at 01:25
  • @Jacob: Please post it as an answer at the canonical duplicate question. – Bergi Mar 02 '16 at 03:01
  • @Bergi, will do, good idea. – Jacob Mar 02 '16 at 04:12

3 Answers3

1

You can use ES6 destructuring with default values to ease some of the burden:

const { 
  aaa: { 
    bbb: { 
      ccc: { 
        ddd = 'none' 
      } = {} 
    } = {} 
  } = {} 
} = (obj || {});

I certainly found this unintuitive at first. Here is the meaning broken down:

  1. As the starting value, use obj, or if it is "falsy", {}.
  2. Get the aaa property, or {} if undefined.
  3. Get the bbb property, or {} if undefined.
  4. Get the ccc property, or {} if undefined.
  5. Declare a ddd constant, assigned the value of the ddd property, or 'none' if undefined.

Note that default values during destructuring only applies to undefined values, not values like null; If you want to handle those cases, more traditional methods will have to be used.

Jacob
  • 77,566
  • 24
  • 149
  • 228
-1

Here is a function I often make use of for JS default settings:

function defaultSetting(check,fallback,current)
    {
        if (!$.isArray(check)) {
            if ($.type(check) === 'string' && check.length > 0) {
                check = [check];
            } else {
                check = false;
            }
        }
        if (false === check || check.length < 1) {
            return false;
        }
        if (!current) {
            current = window;
        }

        var checkThis = check.shift();

        if (check.length > 0) {
            if ((checkThis in current) && $.type(current[checkThis]) === 'object') {
                return defaultSetting(check,fallback,current[checkThis]);
            } else {
                return fallback;
            }
        } else {
            if (checkThis in current) {
                return current[checkThis];
            } else {
                return fallback;
            }
        }
    }

It's actually not ES6 code so probably could be improved somewhat with ES6 syntax. It also uses jQuery for the $.isArray() and $.type() methods, but these lines could be replaced with typeof calls.

in your example above you would call it like ddd = defaultSetting(['aaa','bbb','ccc','ddd'],'none', obj);

Chris O'Kelly
  • 1,863
  • 2
  • 18
  • 35
-2

You could use JSON.stringify(), String.prototype.match()

var hasKey = !!(JSON.stringify(obj).match(/"ddd":/));
guest271314
  • 1
  • 15
  • 104
  • 177