3

So I have a callback function which provides a json object:

function(object){
    var data=object.packet.link.ip.tcp.data;
    console.log(data.toString());
}

The problem I have is that any of packet/link/ip/tcp/data can be "undefined" - my node.js program falls over every time it hits an undefined variable.

I tried putting the declaration of "data" inside try/catch, however I keep getting "undefined" errors - my guess is that I'd need to put object/object.packet/object.packet.link/object.packet.link.ip/etc. in try/catch.

So, I found some elegant coffeescript:

if object?.packet?.link?.ip?.tcp?.data? then doStuff()

which compiles to:

var _ref, _ref1, _ref2, _ref3;

if ((typeof object !== "undefined" && object !== null ? (_ref = object.packet) != null ? (_ref1 = _ref.link) != null ? (_ref2 = _ref1.ip) != null ? (_ref3 = _ref2.tcp) != null ? _ref3.data : void 0 : void 0 : void 0 : void 0 : void 0) != null) {
       //doStuff:
       var data = object.packet.link.ip.tcp.data;
       console.log(data.toString());
}

Yuck!

Now it works perfectly, but I was just wondering if there's a more elegant (readable) way of doing this in pure Javascript?

1
  • 1
    the nice thing about the existential operator in coffeescript is that it is contextually aware (because of the compilation step). tinyurl.com/nqx2aja but I would consider it a code smell to chain it this deep. I like that reduce solution a lot. Commented Nov 13, 2014 at 19:39

3 Answers 3

5

You can do

["packet", "link", "ip", "tcp", "data"]
  .reduce(function (m, i) { if (m) return m[i]; }, object);

You could move the reduce into a function and have get(object, "packet", "link", "ip", "tcp", "data"). It can be pretty, although a simple && solution might be more sensible.

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

3 Comments

At work I made this: get(object, 'packet.link.ip.tcp.data'). It's nearly identical to yours, except there's a .split('.') call.
@Cory, That's great, until you need to use an object {"packet.link.ip.tcp.data": ...}.
Yes, we don't allow such keys normally. If anything like that comes up, we do have an alternative method that takes an array. Since that's identical to your method, it didn't seem worth mentioning until you pointed out that it is necessary in certain cases.
3

If it is just enough to check whether or not you're dealing with truthy values, you might go like

var data = object && object.packet && object.packet.link && object.packet.link.ip; // etc.

still no beauty, but most likely the best you can go for. Of course, you always have the option of introducing the good ol' try..catch clause.

try {
    var data = object.packet.link.ip.tcp.data;
} catch( ex ) { }

Anything "better" than that in terms of "elegance" (whoever that defines) would require a custom written function, which walks step by step through the object properties, checking for existence.

1 Comment

Hi, I tried the try/catch - though I had trouble with the deep nesting and kept getting "undefined" errors...
1
function A(object)
{
 var data = object?object.packet?object.packet.link?object.packet.link.ip?object.packet.link.ip.tcp?  object.packet.link.ip.tcp.data:null:null:null:null:null;
 console.log(data);
}
  • Note:

    If data has null, you can't call toString on null, as null(along with undefined) are the only two primitives which have no object wrappers and subsequently no toString() functions.

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.