Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS checking deep object property existence [duplicate]

I'm trying to find an elegant way to check the if certain deep properties exist in an object. So practically trying to avoid monstrous protective checks for undefined eg.

if ((typeof error !== 'undefined') && 
  (typeof error.responseJSON !== 'undefined') &&
  (typeof error.responseJSON.error) && 
  (typeof error.responseJSON.error.message)) {
      errorMessage = error.responseJSON.error.message;
}

What I'm thinking about is a convenience-function like

if (exists(error.responseJSON.error.message)) { ... }

Any ideas? For convenience, the use of underscore-library is ok for the solution.

like image 289
Marcus Avatar asked Nov 15 '13 14:11

Marcus


2 Answers

There are several possiblities:

Try-catch

try {
  errorMessage = error.responseJSON.error.message;
} catch(e) { /* ignore the error */}

Fails for:

Object.defineProperty(error, 'responseJSON', {
  get: function() { throw new Error('This will not be shown')
});

&&

errorMessage = error && error.responseJSON && error.responseJSON.error && error.responseJSON.error.message;

Fails for:

error.responseJSON = 0;
// errorMessage === 0 instead of undefined

function

function getDeepProperty(obj,propstr) {
  var prop = propstr.split('.');
  for (var i=0; i<prop.length; i++) {
    if (typeof obj === 'object')
      obj = obj[prop[i]];
  }
  return obj;
}

errorMessage = getDeepProperty(error, 'responseJSON.error.message');

// you could put it all in a string, if the object is defined in the window scope

Fails for:

// It's hard(er) to use

function alternative - see comment by @Olical

function getDeepProperty(obj) {
  for (var i=1; i<arguments.length; i++) {
    if (typeof obj === 'object')
      obj = obj[arguments[i]];
  }
  return obj;
}

errorMessage = getDeepProperty(error, 'responseJSON', 'error', 'message');
like image 171
Tibos Avatar answered Nov 03 '22 17:11

Tibos


Try this underscore mixin to look up a variable with a path. It takes an object and string and t

_.mixin({
    lookup: function (obj, key) {
        var type = typeof key;
        if (type == 'string' || type == "number") 
            key = ("" + key).replace(/\[(.*?)\]/, function (m, key) { //handle case where [1] may occur
                return '.' + key.replace(/["']/g, ""); //strip quotes
            }).split('.');
        for (var i = 0, l = key.length; i < l; i++) {
            if (_.has(obj, key[i])) 
                obj = obj[key[i]];
            else 
                return undefined;
            }
        return obj;
    }
});

Now call in your example:

_.lookup(error, 'responseJSON.error.message') // returns responseJSON.error.message if it exists otherwise `undefined`
like image 26
megawac Avatar answered Nov 03 '22 17:11

megawac