3

Say that I have an object that is currently undefined

myObject.property1

It would make sense that any children key off of something that's undefined should also evaluate as undefined, right?

myObject.property1.description

But when I go into the JS console I do:

myObject.property1

undefined

myObject.property1.description

TypeError: Cannot read property 'description' of undefined

Where this gets messy is if I'm doing a conditional:

if(myObject.property1.description){
  console.log("it is defined!");
}else{
  console.log("it is not defined!");
}

I would expect it to console log it is not defined! but instead I get the error and the conditional just flat-out fails. I want it to evaluate as undefined though.

  1. Why doesn't it return undefined as well?
  2. I want the conditional to check for the existence of the value. How do I do this?
fuzzybabybunny
  • 5,146
  • 6
  • 32
  • 58
  • Why can't you check for the existence of the object first? Return undefined if the object is undefined? – Blunderfest Jul 02 '14 at 12:02
  • You've got two separate questions here, one is a asking us to read the language designers minds and the other is asking how to solve a specific problem. Narrow your question to one of them (preferably the on-topic one). – Quentin Jul 02 '14 at 12:03
  • How can it have a *value* if it doesn't exist? – CodingIntrigue Jul 02 '14 at 12:03
  • @Blunderfest Because sometimes you just want to check for the existence of a particular value without having to worry about if the root object exists or not... it should be a given that if the root value doesn't exist then your check for the existence of a child value should return false as well. – fuzzybabybunny Jul 02 '14 at 12:05
  • Why would you expect it to be logged as undefined? You're trying to access properties of something that doesn't exist. It's like trying to read `undefined.name`. – Smeegs Jul 02 '14 at 12:06
  • 1
    The chain is parsed from left to right. `myObject.property1.description` becomes `undefined.description`, and `undefined` is not an object so trying to access its members is not allowed. – JJJ Jul 02 '14 at 12:07

3 Answers3

2

Why doesn't it return undefined as well?

Because that's the specified behavior. Generally speaking, you'd like to catch errors early in your program rather than allowing them to propagate through your program and generate other, perhaps more serious errors elsewhere in your program, where the original source of the error may be very hard to determine. An undefined value is frequently symptom of an error (or at least of something that probably didn't work as expected), and the need to check for them early is a very good thing. It means that you need to write guards against undefined values early in your code, where they occur.

I want the conditional to check for the existence of the value. How do I do this?

A simple solution would look like this:

if(myObject && myObject.property1 && myObject.property1.description){

But of course, if any value in this chain is falsey, e.g. if description is an empty string, this may produce in an unexpected result. If you really just want to see if the value is not undefined, you can do something like this:

if(myObject !== undefined && 
   myObject.property1 !== undefined && 
   myObject.property1.description !== undefined){

Or a bit more verbose, but somewhat more robust:

if(typeof myObject !== "undefined" && 
   typeof myObject.property1 !== "undefined" && 
   typeof myObject.property1.description !== "undefined"){

See Detecting an undefined object property in JavaScript for a full discussion.

Community
  • 1
  • 1
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • Thank you. How would you check then for the very existence of something? – fuzzybabybunny Jul 02 '14 at 12:12
  • I see. To me this sounds like I just discovered one of the downsides of JS - we should be able to check for the existence of object children without first having to check for the existence of the parent (or the parent of that parent, and the parent of **that** parent, and so on and so forth). Because we're doing the crazy cascading multiple check thing that you just did. It would be nice to have something like `if(myObject.property1.description == exists)`, no? – fuzzybabybunny Jul 02 '14 at 12:28
  • @fuzzybabybunny There's no way to do that out of the box. The designers of the language wanted you to be aware of when an object may be undefined and guard against that, even if that meant you would some day have to write code like this. The alternative is just a whole lot worse, if you really think about it. Imagine if after a very long function, you found an `undefined`, but the `undefined` could have originated at any of 100 different places in the code. – p.s.w.g Jul 02 '14 at 12:53
0

The programming language Groovy has what you want, and it calls it the "Safe Navigation" operator. The syntax is to use ?. instead of . when you want this behavior. So you would say

if (myObject?.property1?.description) {
    // ...
}

JavaScript doesn't seem to have anything like this, but this blog post defines a function that will do the check for you. To use it, you would say

if (isSet(myObject, 'property1.description')) {
    // ...
}
Tom Panning
  • 4,613
  • 2
  • 26
  • 47
  • Oh wow, this little bit of code is really really useful and works perfectly! It should totally be included in UnderscoreJS as `_isSet` or something. – fuzzybabybunny Jul 02 '14 at 12:43
0

You can check first for the property1 existence, and then if you have the description property, like this:

var myObject = {
    property1: true
};
if ("property1" in myObject) {
    console.log("property1 is defined!");
    if (myObject.property1.hasOwnProperty("description")) {
        console.log("descrition is defined!");
    }else {console.log("descrition is not defined!");}
    }else {
        console.log(" none is defined!");
    }
Pablor
  • 21
  • 1
  • 2