3

Time and again I have to deal with code like consider following hypothetical example:

if (node.data.creatures.humans.women.number === Infinity) {
  // do-someting
}

Now, problem is that if node is undefined this condition will break. Similarly, it will break if node.data is undefined, node.data.creatures is undefined and so on.

So I end up using following kind of long condition:

if (node && node.data && node.data.creatures && node.data.creatures.humans && node.data.creatures.women && node.data.creatures.humans.women.number === Infinity) {
  // do-someting
}

Now, imagine I have to use parts of that JSON object in many other parts of code too.

The code suddenly starts looking very ugly. Is there a better way of avoiding errors like "Cannot call property of undefined" kind of errors due to the first condition I mentioned such that the code looks better too.

How do you deal with such situations?

Usman
  • 8,227
  • 14
  • 69
  • 103
  • The new Proxy API (quite new and support is limited) can easily solve this: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy – haim770 Mar 07 '16 at 08:25
  • As a note, it is a JavaScript object and not a _JSON object_. JSON representation of data, if you parse that data in JSON format you will get a JavaScript object as result. – t.niese Mar 07 '16 at 08:25

3 Answers3

1

Here is what i'm using, it may not be the "optimizest" way, but, that works for me:

walkObject = function(obj, path) {
  var i = 0,
    part = void 0,
    parts = path.split('.');

  while (obj && (part = parts[i++])) {
    obj = obj[part];
  }
  return obj;
};

The method takes an object, and string containing a dot notation of the property you want to test:

// the object
var obj = { a: { b: {c: [1,2,3], d: "aa"} } };

// tests
console.log("a,b,c", walkObject(obj, 'a.b.c')); // [1,2,3]
console.log("a,b,e", walkObject(obj, 'a.b.e')); // undefined
console.log("z,b,e", walkObject(obj, 'z.b.e')); // undefined
cl3m
  • 2,761
  • 17
  • 21
0

Trying to access a property on undefined is a catchable TypeError, so you can use try..catch:

try {
    if (node.data.creatures.humans.women.number === Infinity) {
        // do something
    }
} catch (e) {
    // property doesn't exist
}
deceze
  • 491,798
  • 79
  • 706
  • 853
0

You can wrap the potentially harmful parts with try - catch:

try {
    if (node.data.creatures.humans.women.number === Infinity) {
        // do-someting
    }
} catch () {
    console.log(e);
}

Another way and maybe a little more elegant would be defining the expected object structure and them merging it with the actual data using for example jQuery.extend().

var nodeTemplate = {
    data: {
        creatures: {
            humans: {...}
        }
    }
}

This will make sure that the structure is as you expect and non-existent fields have some default values.

Then merge it:

node = $.extend(nodeTemplate, node);
martin
  • 85,731
  • 23
  • 174
  • 212