3
\$\begingroup\$

I didn't write this but I noticed it in our codebase at work.

var data = object && object.attribute && object.attribute.data ? object.attribute.data : {};

I get that the programmer is trying to check that the variable object.attribute.datais defined before using it, but is seems like so much repeated code. What's the best way to assign data the value of object.attribute.data if it's defined, otherwise giving it a value of {}?

\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Code Review! Are you asking for alternatives for a ternary operator? I'd bet your question would get more lovin' if you included the whole function instead, and mentioned that you're worried about the readability of the ternary operator. \$\endgroup\$ – Mathieu Guindon Jun 17 '14 at 17:20
  • \$\begingroup\$ The ternary operator isn't my concern here. I'm trying to figure out the best way to check that object.attribute.data is defined before assigning it to another var. object && object.attribute && object.attribute.data seems like a bad practice since it violates "Do not repeat yourself." I don't think the rest of the function is relevant. \$\endgroup\$ – ben.coffee Jun 17 '14 at 17:22
  • 2
    \$\begingroup\$ @blahshaw But it is really no repetition, object and object.attribute and object.attribute.data are three different things having three different values. \$\endgroup\$ – Simon Forsberg Jun 17 '14 at 17:31
  • 1
    \$\begingroup\$ The identifiers in this question are completely generic (akin to foo and bar), making this question off-topic for Code Review. Feel free to ask it again with real identifiers, preferably with sufficient context so that we might even be able to avoid the null-checking problem altogether. \$\endgroup\$ – 200_success Jun 17 '14 at 17:59
  • \$\begingroup\$ @SimonAndréForsberg they all have different values but it is all boilerplate. The only value they care about is the data key and to not throw an exception for dereferencing an undefined value. If they wanted to get a config value out of attribute the same long expression would be repeated. \$\endgroup\$ – pllee Jun 18 '14 at 14:08
4
\$\begingroup\$

Are you looking for this?

var data = object && object.attribute && object.attribute.data || {};

Alternatively, you could create a simple function to safely index objects that may not be defined, such as:

function resolve(value) {
    return function(key) {
        return key ? resolve((value || {})[key]) : value;
    };
}

You'd use it like this:

var data = resolve(object)('attribute')('data')() || {};

If anything in the chain does not exist, it will return undefined. This might be useful if you have deeply nested and unpredictable objects, such as an object resulting from parsing JSON data from a remote resource.

http://jsfiddle.net/VHcdq/1/

\$\endgroup\$
  • \$\begingroup\$ This is a small improvement since it eliminates the need for the ternary operator. However, is there a cleaner way of doing this without needing to write out object && object.attribute && object.attribute.data? \$\endgroup\$ – ben.coffee Jun 17 '14 at 17:23
  • 2
    \$\begingroup\$ @blahshaw, no, not really, unless you want to assume that object and object.attribute exist and can have properties, and go straight for var data = object.attribute.data || {}; \$\endgroup\$ – Dagg Jun 17 '14 at 17:25

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