5
\$\begingroup\$

Is there a better or shorthand way to perform a check on whether or not a variable within (possibly several levels of) an object is null or undefined?

What I would currently do to check is:

if (typeof json !== 'undefined' || typeof json.data !== 'undefined' || typeof json.data.formkeys !== 'undefined') {}

Is there a shorthand way to check for whether or not "json.data.formkeys" is undefined without the concern that one or all of the higher level properties or the object itself might not currently exist?

\$\endgroup\$
4
  • 2
    \$\begingroup\$ I don't have the JS knowledge to tell you in detail, but using a try catch would likely solve this. Take a look here. \$\endgroup\$ Commented Oct 6, 2015 at 16:58
  • \$\begingroup\$ Could you provide a bit more context — where the json is generated from, and what you intend to do with formkeys? \$\endgroup\$ Commented Oct 6, 2015 at 17:00
  • \$\begingroup\$ I can see how in many circumstances that would be appropriate if I'm only looking to perform a task or not perform a task, so that's a great point. In a scenario where I'm going through a few logical checks however (i.e. an else or an else if) the try catch would simply fail... I guess I could place an else within the catch but I think that's probably a poor practice. \$\endgroup\$
    – Ian
    Commented Oct 6, 2015 at 17:03
  • \$\begingroup\$ @200_success You could replace it with lollipops if you want, I'm asking a higher level question about checking for the existence of embedded variables within a JS object. It doesn't matter what I plan on doing with that variable later, what matters is how to return a false instead of an error when json or data are undefined but only checking for the existence of formkeys. \$\endgroup\$
    – Ian
    Commented Oct 6, 2015 at 18:48

3 Answers 3

5
\$\begingroup\$

There's a lot of ways to do this. Here's an exotic (and costly) one:

if(((json || {}).data || {}).formkeys !== void 0){}

As commented, a try-catch will work

// JS has function scope. foo starts its life as declared but undefined
// If the try-catch fails, foo will remain undefined.
try{ var foo = json.data.formkeys; } catch(){}

if(foo !== undefined){}

A longer and possibly better way to do it is to create a resolver function. Most frameworks I have encountered use some form of this in their getter functions so that getting a value from a half-complete path will just return undefined instead of throwing midway.

function resolve(path, root){
  root = root || window;
  return path.split('.').reduce(function(parent, child){
    // A quick check for brevity. You can replace this with a better check
    // and return logic.
    return parent && parent[child];
  }, root);
}

var foo = resolve('json.data.formkeys');

if(foo !== undefined){}
\$\endgroup\$
2
  • \$\begingroup\$ Looks great, and you've given me a few things to look up; I've never used the reduce method. I get what you're doing with the path being passed to the function but can you please explain the root thing? \$\endgroup\$
    – Ian
    Commented Oct 6, 2015 at 22:26
  • \$\begingroup\$ @Ian root is the object where you want to start looking. Without it, the function defaults to the global window (I assume it's a browser). You can pass any object as root, even midway down another object. reduce allows you to carry the result of the last iteration when iterating through the array. Normally used for aggregation, but there are plenty of creative uses for it. \$\endgroup\$
    – Joseph
    Commented Oct 6, 2015 at 22:37
2
\$\begingroup\$

This is one case where eval is not evil, so long as you guard your code:

function getValue(obj, propertyString) {
    if (!/[_$a-z0-9.]/.test(propertyString)) {
        throw new Error("Invalid propertyString");
    }

    try {
        return eval("obj." + propertyString);
    }
    catch (error) {
        return undefined;
    }
}

(sigh) A quote from Dr. Evil seems oddly appropriate for eval (Dr. Eval? ... Nah.):

Well it's true! It's true! You're semi-evil. You're quasi-evil. You're the margarine of evil. You're the Diet Coke of evil. Just one calorie, not evil enough.

Related: eval() isn’t evil, just misunderstood

\$\endgroup\$
2
  • \$\begingroup\$ Eval not evil!?.. but cool, I'll try that out. I think I'm going to have to run speed tests on all of these answers and report back! \$\endgroup\$
    – Ian
    Commented Oct 7, 2015 at 17:18
  • 1
    \$\begingroup\$ @Ian: eval is not not evil. It's just not always evil. \$\endgroup\$ Commented Oct 7, 2015 at 17:30
-1
\$\begingroup\$

Another one:

if ('formkeys' in ((json || {}).data || {})) {}

which is shorter than:

if (((json || {}).data || {}).formkeys !== void 0) {}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.