0

I'm checking an Object (like an Associative Array) to see if a portion of data is available there or not, but I'm getting an undefined error exactly in the if statement where I'm checking if it is undefined or not!

I have an Object like this:

var data = {
    1: {
        2: {
            3: [
                ["a","b"],
                ["c","d"],
            ],
        }
    }
}

I have also tried with double-quotes like: var data = { "1": { "2": { ...

These are the if statements which I've already tried. All of them failed, Firebug is generating TypeError: data[1][2][3] is undefined exactly in the if statement:

if (typeof data[1][2][3] == "undefined") {
if (data[1][2][3] === undefined) { 
// when I have double quotes
if (typeof data["1"]["2"]["3"] == "undefined") {
if (data["1"]["2"]["3"] === undefined) { 

I checked that in jsfiddle.net and it works fine. I tried all the things I could imagine of, however I still don't have any idea why it fails in the if statement.

Update

look at this, oh god:

enter image description here

Mahdi
  • 9,247
  • 9
  • 53
  • 74

5 Answers5

2

If variable[1][2][3] is undefined, the script cannot check whether variable[1][2][3][4] is undefined or not. You should check for undefined for the entire depth of the tree

if(1 in variable)
{
  if(2 in variable[1])
  {
     if(3 in variable[1][2])
     {
       if(typeof variable[1][2][3][4] === 'undefined'){
          // Do something
       }
     }
  }
}
Loupax
  • 4,728
  • 6
  • 41
  • 68
  • The accepted answer is good enough (and more short-readable in the `try-catch` version) :) This just makes absolutely sure that the indexes exist, no matter what value they have, but in your case you shouldn't care about that – Loupax Apr 22 '13 at 09:57
  • probably `if( variable || variable[1] || variable[1][2] /*||...*/ )` might be better suited (more compact and readable). – Christoph Apr 22 '13 at 11:48
1

some remarks, maybe the solution is in between:

Perhaps you want to use the negative version

if (typeof data[1][2][3] !== "undefined") {

since you seem to work on that data in the condition body, so you want to make sure it actually is defined inside your if condition? Atm, the code gets executed if the data is undefined.

Are you using exactly this object in your code or was this only for demonstration purposes? Because if you check data[1][2][3] and data[1][2] is already undefined, trying to access data[1][2][3] will throw an error because you are trying to access a property of a non existing object.

Sidenote: It might be more appropriate to use an array instead of a object if you have numeric indices?

Christoph
  • 50,121
  • 21
  • 99
  • 128
  • Thanks for the answer, I'm using objects because the data is quite nested. However I might switch to the `Array` if I couldn't solve it. Also I was using the negative check, it didn't work ... – Mahdi Apr 22 '13 at 09:13
  • @Mahdi Your console tells you exactly what i was stating with my second guess. You are trying to access `e.Bubbles[2013][3][4]["layer_1"]` but `e.Bubbles[2013][3][4]` does not exist, so it's property `["layer_1"]` of course does not exist too! – Christoph Apr 22 '13 at 09:15
1

Look at your output more closely:

if (typeof e.Bubbles["2013"]["3"]["24"]["layer_1"] === "undefined") {
> TypeError e.Bubbles[2013][3][24] is undefined

i.e., it's crapping out because your test is one level too deep. The ["24"] property doesn't exist so you can't possibly reach the ["layer_1"] property.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
1

If you don't know beforehand whether you have all the hierarchy needed to get to the element you're checking (e.g., you're checking e.Bubbles[2013][3][4]["layer_1"], but e.Bubbles[2013] doesn't exist, and you get TypeError), consider using error catching like this:

try {
    myData = e.Bubbles[2013][3][4]["layer_1"];
} catch (error) {
    myData = undefined;
    console.error("Couldn't get my data", error.name, error.message);
}

if (myData !== undefined) {
    // Do something with the data
}

At a cost of making code much less readable, you could also do something like this:

var _ref, _ref1, _ref2;
if ((_ref = e.Bubbles[2013]) != null ? (_ref1 = _ref[3]) != null ? (_ref2 = _ref1[4]) != null ? _ref2["layer_1"] : void 0 : void 0 : void 0) {
  // We know we have e.Bubbles[2013][3][4]["layer_1"] here
}

But I would recommend error catching.

Anton Strogonoff
  • 32,294
  • 8
  • 53
  • 61
  • yes, I was thinking about that as well, however in my mind `try-catch` is always expensive! I prefer light weight stuff ... but thanks for the suggestion again! – Mahdi Apr 22 '13 at 09:28
  • Well, if you really are dealing with tons of these comparisons on the client, then sure. =) But consider the overhead from multiple `if`s. In Python, for example, throwing an exception would probably be a preferred way to deal with such a problem. – Anton Strogonoff Apr 22 '13 at 09:38
  • Good point, I will make a simple benchmark to see which way is faster in javascript! :) – Mahdi Apr 22 '13 at 09:40
  • I'd added to my answer one way to do that using `if`s, but it's messy and inelegant. It's a JavaScript translation of neat CoffeeScript construction: `if e.Bubbles[2013]?[3]?[4]?["layer_1"]`. Note the question signs, they mean ‘don't go any deeper into the hierarchy if this key is undefined’. – Anton Strogonoff Apr 22 '13 at 09:45
  • That's interesting! Thanks, I guess I will go learn CoffeeScript soon! :D – Mahdi Apr 22 '13 at 09:50
  • Should point that `if(e.Bubbles[2013] != null)` will evaluate to true if the e.Bubbles[2013] is defined but has value of null. In many cases it should be enough, but it's best to know :) – Loupax Apr 22 '13 at 09:50
-1

don't compare it with undefined...

if you want to check if its defined or not then just place it into the IF condition like...

var data = {
    1: {
        2: {
            3: [
                ["a","b"],
                ["c","d"],
            ],
        }
    }
}

if(data[1][2][3])
{
    alert("defined");
}
else
{
    alert("not defined");
}
Virus
  • 2,445
  • 1
  • 14
  • 17
  • 2
    falsy values? it will also trigger on `0`, `""`, `false` - it's always better to check for undefinedness! – Christoph Apr 22 '13 at 09:16
  • `if(!variable)` will check for all the falsy values, not only for undefined. It is not good enough if you need to know if your var is defined or not – Loupax Apr 22 '13 at 09:25
  • You might want to read http://james.padolsey.com/javascript/truthy-falsey/ or http://11heavens.com/falsy-and-truthy-in-javascript for further information on that topic. – Christoph Apr 22 '13 at 09:29