2

Let's say I have an object:

var foo = {'bar1': {'baz1':1}};

And I try to access foo['bar2']['baz2']. If I was just trying to access foo['bar2'], JS would return undefined. But because I'm trying to get the next property after the undefined bar2, JS throws TypeError: Cannot read property 'baz2' of undefined.

Is there some automatic accessor for an object that first checks if baz2 exists in foo before trying to call its properties? I know I could use a try/catch block or an if statement, but I was hoping for a function along the lines of C++'s array::at, that would check for me.

user2000008
  • 120
  • 1
  • 11

4 Answers4

2

Keep in mind this is ONLY for objects, like the one you have shown, and NOT for arrays (ie [0, 1, 2]) but my favorite is this one:

if ('bar1' in foo)

This is even useful for, say, HTML5 feature detection.

if ('localStorage' in window)

I could give you one for arrays too, but I feel like the more logical thing would be to compare its length to a given index. And...not insert undefined values into arrays. Y'know. =p

Katana314
  • 8,429
  • 2
  • 28
  • 36
2

You could write your own pretty easily:

function at(obj, property) {
  var props = property.split('.');
  for(var i = 0; i < props.length; i++) {
    if (typeof obj === 'undefined') {
      return;
    }
    obj = obj[props[i]];
  }
  return obj;
}

var foo = {'bar1': {'baz1':1}};
console.log(at(foo, 'bar1.baz1'));
// => 1
console.log(at(foo, 'bar2.baz2'));
// => undefined
Michael Lehenbauer
  • 16,229
  • 1
  • 57
  • 59
1

You can use the in operator:

if("bar2" in foo) {
   //do stuff with foo['bar2']
}

or you can check to see if foo['bar2'] is undefined:

if(typeof foo['bar2'] !== "undefined") {
    //do stuff with foo['bar2']
}

Also, what you're working with are objects and not arrays (well, they're associative arrays, but also objects in JavaScript).

Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
  • What's the benefit of these over `if (foo["bar2"]) { . . .`? – talemyn Jul 16 '13 at 17:14
  • 2
    `if (foo["bar2"])` can fail spuriously if it maps to `false`, `""`, `0`, or `NaN`. Typically you just want to see if something is defined or not, but using this pattern evaluates the *truthyness* of `foo["bar2"]` and not whether it is defined. – Vivin Paliath Jul 16 '13 at 17:16
  • 1
    Ahh, I see your point . . . so if, for some reason (and, in this example, it looks like it would be highly unexpected) the object were `var foo = {"bar2": false}`, it would return `false`, throwing off the check for "definition". Gotchya . . . thanks. :) – talemyn Jul 16 '13 at 17:24
0

foo['bar2'] && foo['bar2']['baz2'] will do the trick as well.

Yuriy Galanter
  • 38,833
  • 15
  • 69
  • 136