views:

246

answers:

6

If I a reference to an object -

var test = {};

that will potentially (but not immediately) have nested objects, something like -

{ level1:{level2:{level3:'level3'}} };

what is the best way to test for the existence of keys in the most deeply nested objects?

This -

alert(test.level1);

returns 'undefined', but this -

alert(test.level1.level2.level3);

fails.

I'm currently doing something like this -

if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
    alert(test.level1.level2.level3);
}

but I was wondering if there's a better way.

Thanks much.

+4  A: 

how about

try {
   alert(test.level1.level2.level3)
} catch(e) {
 ...whatever

}
stereofrog
+5  A: 

You have to do it step by step if you don't want a TypeError, because if one of the members is null or undefined, and you try to access a member an exception will be thrown.

You can either simply catch the exception, or make a function to test the existence of multiple levels, something like this:

function checkNested(obj /*, level1, level2, ... levelN*/) {
  var args = Array.prototype.slice.call(arguments),
      obj = args.shift();

  for (var i = 0; i < args.length; i++) {
    if (!obj.hasOwnProperty(args[i])) {
      return false;
    }
    obj = obj[args[i]];
  }
  return true;
}

var test = {level1:{level2:{level3:'level3'}} };

checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false
CMS
I started doing something like this, but was hoping for something shorter. But thanks for the answer. +1
patrick dw
+2  A: 

You can easily read an object property at any depth, if you handle the name like a string- 't.level1.level2.level3'.

window.t={level1:{level2:{level3: 'level3'}}};

function deeptest(s){
    s= s.split('.')
    var obj= window[s.shift()];
    while(obj && s.length) obj= obj[s.shift()];
    return obj;
}

alert(deeptest('t.level1.level2.level3') || 'Undefined')

It returns undefined if any of the segments is undefined.

kennebec
A: 

i usually just do something like:


if(typeof test.level1.level2.level3 != 'undefined') {
  alert('woo!');
}
taber
Point is that if say `level2` is `undefined`, and you try to access `level3` (which would try to access a property on undefined) you have a catastrophic failure. You can't do a test for `level3` unless you first test for `level1` and `level2`. That's what I was trying to avoid. The try/catch seemed to be the most concise way.
patrick dw
A: 

I automated the process

if(isset(object,["prop1","prop2"])){
// YES!

}

function isset(object, props){
    var dump;
    try {
        for(var x in props){
            if(x == 0) {
                dump = object[props[x]];
                return;
            }
            dump = dump[props[x]];
        }
    } catch(e) {
        return false;
    }

    return true;
}
Cedric Dugas
A couple things to note. You're doing a `for/in` over an array, which is not recommended. That is really meant for objects. There's no guarantee that the order of execution will be consistent. Also, if you're going to loop over the properties, I probably wouldn't use `try/catch`. I think you'll get better performance taking a `if( props[x] in object )` approach, or `if( object.hasOwnProperty(props[x]) )` if you don't want to include `prototype` properties. My situation was such that I was only interested in the deepest property. That's why I chose `try/catch`.
patrick dw
If you look closely, I move in the object level using the dump variable, I am not staying at level 1
Cedric Dugas
but your right about for/in, my heart is broken :/, it is also slower
Cedric Dugas
+1  A: 

Here is a pattern I picked up from Oliver Steele:

var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );

In fact that whole article is a discussion of how you can do this in javascript. He settles on using the above syntax (which isn't that hard to read once you get used to it) as an idiom.

Gabe Moothart
+1 Interesting approach. Makes me wish I wasn't walking out the door right now. I'll be sure to check out the article when I get back.
patrick dw