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.
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');
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`