views:

59

answers:

5

I have this code:

for(var i in this.units)
 {
 if(this.units[i].x==att.x && this.units[i].y==att.y){}
 //... some more code
 }

and sometimes, randomly, I get an error this.units[i] is undefined.

Anybody got any idea how this is possible?

A: 
for(var i = 0; i < this.units.length; i++){
    if(this.units[i].x==att.x && this.units[i].y==att.y){}
}

You're trying to index this.units using an element from this.units. Use a for loop (shown above) instead.

inkedmn
But what if it's not an array? Your solution won't work if it's an object like "{hello: world}".
Pointy
@Pointy has a point (no pun intended), but I can see how the OP could have led you to this assumption - use of `var i` usually indicates an incrementing integer. But my father always told me not to assume (because it makes an *ass* of *u* and *me*). :-)
Andy E
true. This is an object and therefore I can't iterate with an integer. The "i" is a string in my case.
naugtur
+2  A: 

The loop notation

for (var i in this.units)

gives you the attributes that are defined in the "units" object. Some of those may not have a value, for example if somewhere something had done:

this.units.balloon = null;

Iterating through object properties with "in" loops is pretty risky, unless you really know what's going on with your objects. If your object is actually an array, then you definitely don't want to do it - you should use numeric indexes and a plain loop with a numeric variable. (Even then, there might be null entries!)

Pointy
+1  A: 

Pointy briefly touched upon the probable cause of the issue in his answer and that is that this.units[i] could be null. If you try and access a property on a null value you will get an "is null or not an object" error. In your example this is thrown by the attempt to access this.units[i].x in the if statement. The safest thing to do is to check and see if it's a null value first:

for(var i in this.units) 
{ 
    if (this.units[i] === null)
        continue;

    if(this.units[i].x==att.x && this.units[i].y==att.y){} 
    //... some more code 
}

You should also check out the other points of his answer, most importantly that for...in loops aren't ideal for arrays.

Andy E
+1  A: 

MY Bad: I thought this question was in python!

You are probably doing something like:

del this.units[i]

somewhere in your code or altering your collection in some way. This is a No-No during iteration.

drozzy
It's delete, not del, but I think You might be right. Still I don't see why deleting only the current element after the if would cause problems.
naugtur
@naugtur: I doubt `delete` is your problem, if you `delete` a property before the `for...in` loop, the property is gone and won't be iterated over. You'd have to delete after the for statement and before the if statement for it to throw the error you're getting at that part of the code.
Andy E
You misunderstood. I sometimes delete current element this.units[i] in the code part inside the loop, after if statement. I wonder if it changes anything in the loop behaviour.
naugtur
+1  A: 

First of all, if your iteration is over an object, don't use "i" as the iteration variable, use prop or key to make it clear that you're iterating properties, not indexes.

Second, it sounds like you can simply debug and find out what element in your object is empty. Without the full code, it's hard to help you. I think the problem is that you are deleting by doing

obj.myProp = null;

Which means that a for in loop will still iterate over that property. However, if you use

delete obj.myProp;

myProp will not be iterated in a for in loop.

Juan Mendes
I think you mean `delete obj.myProp;`. `del` is not a keyword in JavaScript.
Andy E
I do use delete.
naugtur
@naugtur want to post more context?
Juan Mendes
I should have added this info (using delete) but anything else is irrelevant.
naugtur