27

Is there a simpler way than using ___ in object to check the existence of each level of an object to check the existence of a single member?

More concisely: How can I check if someObject.member.member.member.value exists?

JustcallmeDrago
  • 1,885
  • 1
  • 13
  • 23

8 Answers8

36

In general, you can use if(property in object), but this would be still cumbersome for nested members.

You could write a function:

function test(obj, prop) {
    var parts = prop.split('.');
    for(var i = 0, l = parts.length; i < l; i++) {
        var part = parts[i];
        if(obj !== null && typeof obj === "object" && part in obj) {
            obj = obj[part];
        }
        else {
            return false;
        }
    }
    return true;
}

test(someObject, 'member.member.member.value');

DEMO

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Looks good. I like the looping approach, but how does the __typeof obj === "object"__ help exactly? Isn't it true that typeof can return object for null and array too? – JustcallmeDrago Jan 13 '11 at 02:52
  • @JustcallmeDrago: True... would not matter so much for the array though, but it would fail for `null`. So it is maybe better to add a check for null as well. I added the test because `'value' in ` would throw an error. Added `null` test. – Felix Kling Jan 13 '11 at 02:58
  • @Felix: I see. I really like the string as an argument, but also the simplicity of Patrick's answer. Is his as safe as yours? Is it as fast? – JustcallmeDrago Jan 13 '11 at 03:01
  • @JustcallmeDrago: His is probably faster. But you would have problems with the last value. The result of his code is either `undefined` or the value of the last property. If this is set to `undefined` the you cannot distinguish. But assuming that you never set a value like that, it should be save. Honestly, I find it a bit harder to read though, and if you want to make reusable you'd have loops again... but both will work. – Felix Kling Jan 13 '11 at 03:06
  • I think I'll do some sort of check like his, but use a loop like yours. Thanks a lot! – JustcallmeDrago Jan 13 '11 at 03:22
  • @Felix: I think I've got it. Would you look this over? http://jsfiddle.net/7nPnz/4/ – JustcallmeDrago Jan 13 '11 at 03:52
  • @JustcallmeDrago: Looks ok to me. I would just replace the regular expression search with `indexOf('.')`. And I'm not sure but I guess that the recursion is slower in general. – Felix Kling Jan 13 '11 at 04:14
  • It would be nice if this also supported array notation like `test(someObject, 'member['member'].member[3].value');`. I'm wondering if this is a corner case for using `eval`. – Jan Apr 25 '11 at 11:39
  • 2
    Sorry to interrupt but... somebody here mentioned "Patrick's answer" as being faster. Err... where is this answer? :-? – Merc Nov 01 '13 at 02:05
  • The only solution that works for me! Thanks – Britto Jan 03 '22 at 01:22
7

You could also try/catch TypeError?

try {
  console.log(someObject.member.member.member.value);
} catch(e) {
  if (e instanceof TypeError) {
    console.log("Couldn't access someObject.member.member.member.value");
    console.log(someObject);
  }
}
Oscar Gillespie
  • 117
  • 1
  • 9
4

Here's one way: http://jsfiddle.net/9McHq/

var result = ((((someObject || {}).member || {}).member || {}).member || {}).value;

alert( result );
user113716
  • 318,772
  • 63
  • 451
  • 440
3

Check out lodash-deep’s deepHas https://github.com/marklagendijk/lodash-deep#_deephascollection-propertypath

And this too https://github.com/danielstjules/hoops

ojreadmore
  • 1,465
  • 2
  • 17
  • 33
2

Theres a safeRead function defined here on thecodeabode which allows a safeRead of nested properties i.e.

safeRead(foo, 'bar', 'jim', 'jam');

if any of the properties are null or undefined a blank string is returned - useful for formatting / string interpolation

Ben
  • 1,203
  • 13
  • 8
2

Something like (warning: untested code ahead)

var testProperty = function(obj, proplist) {
   for (var i=0; i < proplist.length; i++) {
      if (obj.hasOwnProperty(proplist[i])) {
         obj = obj[proplist[i]];
      } else {
        return false;
      }
   }
   return true;
}
Michael Lorton
  • 43,060
  • 26
  • 103
  • 144
2
if (someObject.member && someObject.member.member &&
    someObject.member.member.member && someObject.member.member.member.value) ...

or similarly:

var val = foo.bar && foo.bar.jim && foo.bar.jim.jam && foo.bar.jim.jam.value;

This will not 'work' if any particular value happens to be null, false, 0, or "" (an empty string), but with the possible exception of the final value, this seems unlikely to be the case.

Also, note that typeof ____ !== "undefined" is not the correct test to see if an object has a property. Instead you should use ___ in object, e.g. if ("member" in someObject). This is because you can set a property to an explicit value of undefined, which is different from removing it with delete someObject.member.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
0

If you can use lodash library, it has a very elegant solution, hasIn.

_.hasIn(someObject, 'member.level1.level2.level3');

for example,

var obj = {'x': 999, 'a': {'b': {'c': 123, 'd': 234}}}
// => undefined

_.hasIn(obj, 'x')
// => true

_.hasIn(obj, 'a.b.d')
// => true

_.hasIn(obj, 'a.b.e')
// => false
kmonsoor
  • 7,600
  • 7
  • 41
  • 55