Lets say I parse a JSON object from a 3rd party source:
var myObject = {
person_list: [
{ black_hair: {
list: [
'bob',
'john',
'allen'
]}
}
]
};
But if the structure suddenly changes or perhaps the data response was corrupt, how can I check the existence of the in depth parts of the structure?
I can do
if ( myObject.person_list.black_hair.list !== undefined ) {
// do stuff
}
But maybe black_hair
doesn't exist in some cases. If it's missing from the object, then I get a Uncaught TypeError: Cannot read property 'list' of undefined
. So the only way I can think of to check if the entire structure is plete is to check if each level is defined:
if ( myObject.person_list !== undefined ) {
if ( myObject.person_list.black_hair !== undefined ) {
if ( myObject.person_list.black_hair.list !== undefined ) {
// do stuff
}
}
}
But that is a little bit ridiculous. Is there a simple way to handle this in JavaScript? Is a try, catch the best approach?
Lets say I parse a JSON object from a 3rd party source:
var myObject = {
person_list: [
{ black_hair: {
list: [
'bob',
'john',
'allen'
]}
}
]
};
But if the structure suddenly changes or perhaps the data response was corrupt, how can I check the existence of the in depth parts of the structure?
I can do
if ( myObject.person_list.black_hair.list !== undefined ) {
// do stuff
}
But maybe black_hair
doesn't exist in some cases. If it's missing from the object, then I get a Uncaught TypeError: Cannot read property 'list' of undefined
. So the only way I can think of to check if the entire structure is plete is to check if each level is defined:
if ( myObject.person_list !== undefined ) {
if ( myObject.person_list.black_hair !== undefined ) {
if ( myObject.person_list.black_hair.list !== undefined ) {
// do stuff
}
}
}
But that is a little bit ridiculous. Is there a simple way to handle this in JavaScript? Is a try, catch the best approach?
Share Improve this question asked Jul 24, 2014 at 3:05 Jake WilsonJake Wilson 91.2k96 gold badges260 silver badges371 bronze badges 5-
4
did you tried this
if(myObject && myObject.peson_list && myObject.peson_list.black_hair && myObject.peson_list.black_hair.list){}
– Mritunjay Commented Jul 24, 2014 at 3:08 - 2 Could you use jQuery.extend() to create a base-level object? The values might be empty but at least they wouldn't be undefined. It would depend on how large you're expecting myObject to be – jasonscript Commented Jul 24, 2014 at 3:09
-
1
Actually you don't expect the structure to be broken. So I'd say this is a model case for when to use a
try-catch
statement. Otherwise you'd check for way too many things and probably you overlook something. Like what ifperson_list
isn'tundefined
butnull
? – Robert Commented Jul 24, 2014 at 4:32 -
1
The question is flawed in that the given structure of
myObject.person_list.black_hair.list
is undefined anyway, sinceblack_hair
is not a property ofperson_list
. but rather a property of the object which is the first element in theperson_list
array, so the actual "structure" of this object ismyObject.person_list[0].black_hair.list
so answers given so far would correctly yieldfalse
if testing for the structure ofmyObject.person_list.black_hair.list
– chiliNUT Commented Jul 24, 2014 at 4:39 - @chiliNUT good point! I've updated my answer. – S. A. Commented Jul 24, 2014 at 5:07
4 Answers
Reset to default 4You could define a function to check the full structure for you:
function defined_structure(obj, attrs) {
var tmp = obj;
for(i=0; i<attrs.length; ++i) {
if(tmp[attrs[i]] == undefined)
return false;
tmp = tmp[attrs[i]];
}
return true;
}
//...
if(defined_structure(myObject, ['person_list', 0, 'black_hair', 'list']) {
// Do stuff
}
The first parameter is the object with structure to be checked, and the second one is an array with the name of the nested properties.
Update:
As pointed out by @chiliNUT, person_list
is an array. Anyway, this approach works by adding the index of the item you want to check (i.e. ['person_list', 0, 'black_hair', 'list']
).
you can use this function I wrote to check whether the property is set. You just need to pass the path to the property as a string.
// Check if nested object properties exist on unlimited levels
// param: str 'obj.property.property'
function isset (property)
{
// split path to object property
var properties = property.split('.');
var obj = this;
//loop through each portion of the path checking if it exists
for (var i = 0; i < properties.length; i++)
{
var current_property = properties[i];
var next_property = i < properties.length - 1 ? true : false;
// IF current property exists then we need to check the next level
if (obj[current_property] !== null && typeof obj[current_property] === 'object' && next_property)
{
obj = obj[current_property];
continue;
}
return obj.hasOwnProperty(current_property);
}
}
if ( isset('myObject.person_list.black_hair.list')) {
// do stuff
}
just a bit better way with meta object which maps the expected format
var meta = {
name: "person_list",
type: [],
ponent: [{
name: 'black_hair',
type: {},
ponent: {
name: 'list',
type: []
}
}]
};
var myObject = {
person_list: [{
asdfa: {
list: [
'bob',
'john',
'allen']
}
}]
};
function defined(meta, obj) {
if (meta.name == 'list' && obj[meta.name] && obj[meta.name].length) {
return true;
}
if (!obj[meta.name]) {
return false;
};
if (Object.prototype.toString.call(meta.type) === '[object Array]' && !obj[meta.name].length) {
return false;
} else if (Object.prototype.toString.call(meta.type) === '[object Array]' && obj[meta.name].length) {
for (index in obj[meta.name]) {
return defined(meta.ponent[index], obj[meta.name][index]);
}
} else if (Object.prototype.toString.call(meta.type) === '[object Object]') {
return defined(meta.ponent, obj[meta.name]);
}
}
console.log(defined(meta, myObject));
DEMO
you can do like
if ( myObject?.person_list?.black_hair?.list !== undefined ) {
// do stuff
}
You can refer this : Optional chaining