0

I have a big array which contains all kind of types (booleans, arrays, null, ...), and I am trying to access their propiety arr[i].length, but some of them obiously fail to have length.

I wouldn't mind if the guys missing length returned undefined (I could simply use arr[i].length||0 or something like that), but this is not the case, the whole thing crashes with some values (null or undefined for example).

var i, len, arr;

arr = [true, ["elm_0"], 99, "abc"]; //crashes if you add 'null' or 'undefined'

for(i = 0, len = arr.length ; i<len ; i++){
    document.write(arr[i].length + "<br>");
}

document.write("I was executed");
  • What other vars will crash besides null and undefined?
  • How to prevent this from happening?
ajax333221
  • 11,436
  • 16
  • 61
  • 95

5 Answers5

2

You're going to get a TypeError stating undefined has no properties. Nothing you can do here but wrap it in a try catch for TypeErrors.

Note that this is the same reason referencing a property on something that evaluates to undefined will return a ReferenceError: undefined should never have properties.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • there seem to be other ways to prevent this without catching anything, your 'nothing you can do... except catch' will start to look incorrect-er every time someone post a working answer D: – ajax333221 Nov 24 '12 at 19:13
  • @ajax333221 You're taking that a bit too literally. What I mean is that there is no way to prevent an error from popping up when you try to evaluate a property on `undefined` or `null`. The other answers are just ways of avoiding that evaluation (checking for null undefined and skipping the iteration etc.). – Asad Saeeduddin Nov 24 '12 at 19:15
  • you are right, but well you can't denny at first glance it looks like you are saying there is not other possible work around except catching, my confusion is understandable – ajax333221 Nov 24 '12 at 19:21
  • @ajax333221 I apologise sincerely. – Asad Saeeduddin Nov 24 '12 at 19:24
2

You can just check for null without doing a type specific check, that will catch undefined values also.

var i, len, arr;
arr = [true, ["elm_0"], 99, "abc", null, undefined];
for (i = 0, len = arr.length; i < len; i++) {
    if (arr[i] != null) {
        console.log(arr[i].length);
    }
}
console.log("I was executed");
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • @Asad: Yes, I already found that out, and adjusted the answer. :) – Guffa Nov 24 '12 at 18:56
  • something like that will work, since you are using a weak check I think there wont be much difference if I use `if(arr[i])` or something like that, which is basically what _Paul S._ did so I gave him a +1 too – ajax333221 Nov 24 '12 at 19:21
  • @ajax333221: Yes, you will get the same result for most values, but for example the value `""` will be evaluated to false eventhough it is an object, and actually has a `length` property. – Guffa Nov 24 '12 at 19:29
  • those will go to the `else` and I think giving falsey values 0 len is safe, I wrote `(arr[i])?arr[i].length||0:0` which is exactly what Paul said, I am starting to like his answer more, and you have plenty rep, and I should not feel sorry, changing accepted answer is not wrong please respect my opinion I have this power and help please dont be mad, trust me I feel worse than you – ajax333221 Nov 24 '12 at 19:35
  • @ajax333221: NP. That solution works too, as long as you are aware of the difference, and it doesn't cause a problem in your situation. – Guffa Nov 24 '12 at 20:39
1

Check for arr[i] before arr[i].length

var i, len, arr;

arr = [true, ["elm_0"], 99, "abc"];

if(arr) for(i = 0, len = arr.length || 0 ; i<len ; i++){
    if(arr[i]) document.write((arr[i].length || 0) + "<br>");
    else document.write(0 + "<br>"); // what to do if no arr[i]
}

document.write("I was executed");

You can use a ternary operator, too (arr[i]?arr[i].length||0:0)

Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • I am sure my arr will always be an arr, the first `len=...||0` is not really necessary, but I am definetely using the `arr[i]?arr[i].length||0:0` line – ajax333221 Nov 24 '12 at 19:39
  • Note: This will skip some values that actually have a length property, like `""`. – Guffa Nov 24 '12 at 20:37
0

Try this:

var i, len, arr;

arr = [true, ["elm_0"], 99, "abc"]; //crashes if you add 'null' or 'undefined'

for(i = 0, len = arr.length ; i<len ; i++){

try{
console.log(arr[i].length);
}Catch(e){console.log(0);}
}

console.log("I was executed");
Fr_nkenstien
  • 1,923
  • 7
  • 33
  • 66
-1

If your only goal is to determine if one of these objects is an array, then instead of:

for(i = 0, len = arr.length ; i<len ; i++){
    console.log(arr[i].length);
}

You should try this:

for(i = 0, len = arr.length ; i<len ; i++){
    if (arr[i] instanceof Array)
        console.log(arr[i].length);
}
username tbd
  • 9,152
  • 1
  • 20
  • 35