1

Some times when I call methods of this object I got "Oops" error because "i" refers to unexisted attribute. How its possible?

m.derp();
m.herp(); // Sometimes throws error

Methods:

this.movements = new Array();
this.herp = function() {
    for (var i in this.movements) {
        if (!(this.movements[i] instanceof Movement)) {
            throw new Error("Oops"); // this.movements[i] is undefined
        }
    }
}
this.derp = function() {
    var newArray = new Array();
    for (var i in this.movements) {
        if (!this.movements[i].isFinished()) {
            newArray.push(this.movements[i]);
        }
    }
    this.movements = newArray;
}
Sorc
  • 67
  • 7
  • http://stackoverflow.com/questions/500504/javascript-for-in-with-arrays – SMathew Jul 05 '12 at 22:36
  • Not beeing a instance of Movement does not mean it is undefined - try to alert it and you'll see... – Bergi Jul 05 '12 at 22:37
  • throw new Error("Oops"); // Java's new incarnation lol – SMathew Jul 05 '12 at 22:39
  • @elclanrs: It doesn't, actually. You're better off, usually, with `[]`. ;-) `Array` can be shadowed. `new Array` also has functionality that `[]` doesn't have (the ability, if you give it **one** argument, to set the `length`). That's only marginally useful, and confusing given that more than one argument does something entirely different, but they definitely aren't `===`. :-) – T.J. Crowder Jul 05 '12 at 22:44
  • Oh, yeah, you're right, forgot about `new Array(n)`. – elclanrs Jul 05 '12 at 23:07

3 Answers3

3

For arrays, you should not be using for-in. It's a general enumerator that includes all enumerable properties, including those inherited via prototype.

You should do this...

for (var i = 0; i < this.movements.length; i++) {

Any properties added to Array.prototype or Object.prototype will be encountered when using for-in.

If you only want numeric indices, then the for statement is the correct statement to use. ...except in certain narrow circumstances, as noted by T.J. Crowder below.

  • *"If you only want numeric indices, then the for statement is the correct method."* Not ***always***. In a sparse array, you're better off with `for..in` using `hasOwnProperty` and `if (String(Number(i)) === i)`. Just don't expect that it will always work in any given order. :-) – T.J. Crowder Jul 05 '12 at 22:39
  • @T.J.Crowder: Not necessarily. If you still need to guarantee an ordered sequence, you'll need `for`. EDIT: ...just saw your update. –  Jul 05 '12 at 22:41
  • I wonder because first `this.movements` refers to array `{0:obj,1:obj,2:obj}` and after call `m.derp()` it's refers to new array `{0:obj,1:obj}` but in `m.herp()` index 2 still there and `for-in` returns it. Don't know why, probably this is kinda V8 optimization or something o_o – Sorc Jul 05 '12 at 22:51
  • @user1505315: I'd have to see how/where you're logging, but Chrome's console can be funny. When displaying an object, it doesn't necessarily show the state of the object at the time of logging. Future modifications may be reflected in the console. To get a better snapshot, you can shallow clone the Array. `console.log(this.movements.slice())` –  Jul 05 '12 at 22:57
  • ...or to see if there are prototyped enumerable properties, give this a try... `for(var p in []) console.log(p);`. If you get an alert, then there are prototypal extensions. –  Jul 05 '12 at 22:59
1

Normally you should not use for-in for arrays - that construct is more for use on objects. Use a traditional for loop:

for (var i=0, len=this.movements.length; i<len; i++) //do stuff...

See this question for more info on why this is.

Community
  • 1
  • 1
Mitya
  • 33,629
  • 9
  • 60
  • 107
  • *"Never use for-in for arrays"* There are perfectly good and valid reasons for using `for..in` on arrays. (Sparse arrays are one good example.) You do have to understand what it actually does, and handle that correctly. – T.J. Crowder Jul 05 '12 at 22:41
  • True, there are occasionally times, just not often. I've edited the post to be a little less pentecostal in tone. – Mitya Jul 05 '12 at 22:44
  • 1
    @ Utkanos: *"...pentecostal in tone..."* LOL!! – T.J. Crowder Jul 05 '12 at 22:46
1

You should not use for in for iterating an array, because actually you are iterating on every property of an array object, also the ones that are inherited (I'm not sure if there are any). use simple loop:

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

}
Headshota
  • 21,021
  • 11
  • 61
  • 82