Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid 'undefined' errors in nested objects [duplicate]

I'm looking for some good strategies for avoiding errors in JavaScript when using dot notation to call the children of children in objects that may or may not exist.

At the bottom of the code snippet below is an example of a solution that works, but is inelegant (at best).

It would be great to see some native JavaScript solutions or even external libraries that can help avoid this kind of error.

const object1 = {
  foo: {
    bar: {
      baz: 'payload'
    }
  }
};


const object2 = {};

const array = [object1, object2];

// this will fail on object2 because obj.foo is undefined
array.forEach(obj => {
    if (obj.foo.bar.baz) {
      console.log(obj.foo.bar.baz);
     } else {
      console.log('undefined');
     }
  } 
);

// this will work, but it's horrible to write all those nested if statements.
array.forEach(obj => {
    if (obj) {
      if (obj.foo) {
        if (obj.foo.bar) {
          if (obj.foo.bar.baz) {
          console.log(obj.foo.bar.baz);
          }
        }
      }
    } else {
      console.log('undefinded');
    }
  }
);
like image 323
Gerard Avatar asked Jun 22 '18 21:06

Gerard


People also ask

What is nested object in JavaScript?

Nested objects are objects that are inside another object. You can create nested objects within a nested object. In the following example, Salary is an object that resides inside the main object named Employee . The dot notation can access the property of nested objects. JavaScript.


3 Answers

Lodash already did it for us: https://lodash.com/docs#get

const object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// => 3

_.get(object, ['a', '0', 'b', 'c']);
// => 3

_.get(object, 'a.b.c', 'default');
// => 'default'
like image 133
Jordan Enev Avatar answered Oct 18 '22 19:10

Jordan Enev


No sure if that's enough of an improvement but you can use a single if statement with the following condition:

(obj && obj.foo && obj.foo.bar && obj.foo.bar.baz)

This will check if obj.foo.bar.baz exists.

const array=[{foo:{bar:{baz:'payload'}}},{}]

array.forEach(obj => {
  if (obj && obj.foo && obj.foo.bar && obj.foo.bar.baz) {
    console.log(obj.foo.bar.baz);
  } else {
    console.log('undefined');
  }
});
like image 36
Ivan Avatar answered Oct 18 '22 19:10

Ivan


You could chain all checks with logical AND &&.

const
    object1 = { foo: { bar: { baz: 'payload' } } },
    object2 = {},
    array = [object1, object2];

array.forEach(obj => {
    if (obj && obj.foo && obj.foo.bar && obj.foo.bar.baz) {
        console.log(obj.foo.bar.baz);
    } else {
        console.log('undefined');
    }
});

For an automatic check, you could take an array of keys and return either the value or undefined.

const
    getValue = (object, keys) => keys.reduce((o, k) => (o || {})[k], object),
    object1 = { foo: { bar: { baz: 'payload' } } },
    object2 = {},
    array = [object1, object2];

array.forEach(obj => console.log(getValue(obj, ['foo', 'bar', 'baz'])));
like image 28
Nina Scholz Avatar answered Oct 18 '22 20:10

Nina Scholz