2

Consider I have a object like this:

Obj.Boo.Foo.Zoo

Ok now if I want to be sure that zoo has a value and not empty, I should do:

if(Obj != null && Obj.Boo != null && Obj.Boo.Foo != null && Obj.Boo.Foo.Zoo != null) {
    //blah blah
}

And If I have more nested objects after Zoo, I should expand the if and the code becomes a little bit malformed.

Is there any better way for doing that type of conditions?

2
  • Is this Java or javascript? Commented Feb 12, 2013 at 5:49
  • @MikhailVladimirov JavaScript, question tagged with JavaScript also. Commented Feb 12, 2013 at 5:51

3 Answers 3

3

I keep a little function I call chainGet(obj, chain, default) around for situations just like this:

function chainGet(obj, chain, dflt) {
    if (typeof chain === "string")
        chain = chain.split(".");
    var result = obj;
    for (var i = 0; i < chain.length; i += 1) {
        if (result === undefined)
            break;
        result = result[chain[i]];
    }
    return result === undefined? dflt : result;
}

For example:

> chainGet({ foo: 42 }, "foo")
42
> chainGet({ foo: 42 }, "bar", "x")
'x'
> chainGet({ foo: { bar: 42 }}), "foo.bar")
42

This even works with arrays:

> chainGet([{ foo: [42] }], [0, "foo", 0])
42

Of course, long chains of dotted accesses are a code smell, so caution should be exercised when using them… but sometimes you've just got to do it ;)

Sign up to request clarification or add additional context in comments.

4 Comments

Does this even work for you, @AfshinMehrabani? You can't use default, and result is changed to obj[chain[i]], which means its never going deeper into the object. I tried to change the code, David, but it looks like you declined it.
Err, yes, that's a bug in my code :) I didn't decline the edit… I never even saw it. I guess that was the reviewers.
What about the default? Isn't that a reserved keyword? You should rename default to something else.
JavaScript does magic to make sure that's okay… But, ya, it probably would be a good idea to change it. Done.
0

A bad practice if you dont really need to handle such a case would be to try accessing the Object in a try catch statement

try{
    // access Obj.Boo.Foo.Zoo
}
catch{
    // catch a NullReferenceException
}

A better way would be to modify your getters and setters so that the parent object throws a suitable exception or handles this once you try to access a subobject and its null. In this case it would be enough to check the first object.

3 Comments

Yeah I thought so but, as you said, it's not a good approach.
There are situations (ex, where performance is important) where it's not too bad if you do this: try { var x = foo.bar.baz; } catch(e) { … }; x(); -- making sure to use the value outside of the try block, so the only exception that will be caught is the npx from the chain lookup.
@AfshinMehrabani No body knows your code as you do, so you have to decide for the specific case, in a new code i would do it the right way, you should design your program in a way which ensures that these ibjects are assigned if its desired or you say iw ill allow cases where these can be nulls so you check them in the getter methods.
0

It can be achieved without using a function. Shortcut method could be -

if(((((Obj || {}).Boo || {}).Foo || {}).Zoo || {}) != {}) {
    // Zoo has a value and not empty
}

Or the ES6 way -

const checkNull = (keys, Object) =>
  keys.reduce((Obj, o) =>
    (Obj && Obj[o]) ? Obj[o] : null, Object)

console.log(checkNull(['Boo', 'Foo', Zoo], Obj))
// [Value of Zoo]
console.log(checkNull(['Boo', 'Foo1', Zoo], Obj))
// null

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.