JavaScript, elegant way to check nested object properties for null/undefined

JavascriptObjectJavascript Objects

Javascript Problem Overview


a "problem" which i have every now and then is that i have an object e.g. user = {} and through the course of using the app this gets populated. Let's say somwhere, after an AJAX call or something i do this:

user.loc = {
    lat: 50,
    long: 9
}

At another place i want to check if user.loc.lat exists.

if (user.loc.lat) {
    // do something
}

If it does not exists, this will cause an error. If user.loc.lat is undefined, user.loc of course is undefined as well.

"Cannot read property 'lat' of null" - Dev Tools error

That means I need to check it like this:

if (user.loc) {
    if (user.loc.lat) {
        // do something
    }
}

or

if (user.loc && user.loc.lat) {
    // do something
}

This isn't really pretty and the bigger my objects are the worse it gets - obviously (imagine 10 levels of nesting). It kind bums me that if(user.loc.lat) isn't just returning false if user.loc is undefined as well.

What's the ideal way to check situations like this?

Javascript Solutions


Solution 1 - Javascript

You can use an utility function like this:

get = function(obj, key) {
    return key.split(".").reduce(function(o, x) {
        return (typeof o == "undefined" || o === null) ? o : o[x];
    }, obj);
}

Usage:

 get(user, 'loc.lat')     // 50
 get(user, 'loc.foo.bar') // undefined

Or, to check only if a property exists, without getting its value:

has = function(obj, key) {
    return key.split(".").every(function(x) {
        if(typeof obj != "object" || obj === null || ! x in obj)
            return false;
        obj = obj[x];
        return true;
    });
}

if(has(user, 'loc.lat')) ...

Solution 2 - Javascript

You can combine the checks using lazy and:

if(user.loc && user.loc.lat) { ...

Or, you use CoffeeScript. And ES2020 has new syntax ( Nullish coalescing Operator ).

user.loc?.lat?. '...'

which would run the checks for loc property and safeguard against empty objects.

Solution 3 - Javascript

Well, javascript has try-catch. Depending on what you actually need to do (i.e. what your else statement would look like if it's undefined), that may be what you want.

example:

try {
   user.loc.lat.doSomething();
} catch(error) {
   //report
}

Solution 4 - Javascript

Try this if(user && user.loc && user.loc.lat) {...}

You can check value of null and undefined using typeof

If .loc has value false than you can try

if(user && user.loc && typeof(user.loc)!=="undefined"){...}

If you have a huge nested object than have a look at

Source.

function checkNested(obj /*, level1, level2, ... levelN*/) {
  var args = Array.prototype.slice.call(arguments),
      obj = args.shift();

  for (var i = 0; i < args.length; i++) {
    if (!obj.hasOwnProperty(args[i])) {
      return false;
    }
    obj = obj[args[i]];
  }
  return true;
}

var test = {level1:{level2:{level3:'level3'}} };

checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false

Update: Try lodash.get

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionProblemsOfSumitView Question on Stackoverflow
Solution 1 - JavascriptgogView Answer on Stackoverflow
Solution 2 - JavascriptpunundView Answer on Stackoverflow
Solution 3 - JavascriptMarioDSView Answer on Stackoverflow
Solution 4 - JavascriptAamir AfridiView Answer on Stackoverflow