3

What is going wrong in this bit of code that i always get the unexpected output?

var foo = [3,4,5];

for ( var i in foo ) {
      if ( i == 1 ) {
     foo.unshift(6,6);
         }
  document.write('item: '+foo[i]+"<br>")
  }
output:
item: 3
item: 6
item: 3

Can i get an appropriate reason for this?thank u

6
  • 2
    You're using for-in to iterate your array instead of for. This causes a variety of problems in JavaScript, and you've come across one. Since for-in doesn't guarantee any particular order of enumeration, it's including the unshifted value. A different browser may not include it... and both would be correct. Commented Apr 12, 2013 at 5:19
  • Why i m get down voted Commented Apr 12, 2013 at 5:44
  • @amnotiam—interesting though that only one of the new values is included, even in IE where I would expect to see both at the end. Commented Apr 12, 2013 at 5:45
  • @RobG: Yeah, maybe IE treats Arrays a little differently... especially since unshift is used. Commented Apr 12, 2013 at 5:46
  • @amnotiam—IE typically returns properties in the order they were added, but it gives the result in 555k's post because 0 has already been visited and written when it had a value of 3 before being changed to 6, then item 1 is changed to 6 before it's written, then it writes the rest of the array. Fx doesn't visit the last 2 members as they were added after the for..in loop started. And as you say, both results are consistent with ECMA-262. Commented Apr 12, 2013 at 14:40

2 Answers 2

1

The output i got in IE8 is this

item: 3
item: 6
item: 3
item: 4
item: 5

Which is correct. If you want Fully updated value after the unshift use another loop

var foo = [3,4,5];
  for ( var i in foo ) {
      if ( i == 1 ) {
     foo.unshift(6,6);
         }
  }
  for ( var i in foo )
    document.write('item: '+foo[i]+"<br>")

Which will give

item: 6
item: 6
item: 3
item: 5
item: 4

In your code when you call document.write('item: '+foo[i]+"<br>") with i = 0 Your foo[0] is 3 For i=1 after unshift foo == [6,6,3,4,5] ie foo[1] is 6.

Sign up to request clarification or add additional context in comments.

5 Comments

where is the second item i.e 6
It's neither correct nor incorrect. The implementations get to decide how to deal with new properties added during enumeration, as well as the overall order of enumeration.
Because you're using IE. :-) There is no "correct" answer since the order of iteration over object properties using for..in is implementation dependent. And as you've shown, it really is different in different implementations.
@RobG Thanks for pointing it out that its implementation dependent. I tested it only in IE :-). I added that in my answer
@Maizere: What worked? Are you not comprehending the fact that the order of enumeration is not guaranteed? The browser under some condition could decide to change the order altogether, and it wouldn't be a bug. The real answer to your question is that for-in shouldn't be used like you're using it.
0

for..in should not be used to iterate over an Array where index order is important. Array indexes are just enumerable properties with integer names and are otherwise identical to general Object properties.
There is no guarantee that for...in will return the indexes in any particular order and it will return all enumerable properties, including those with non–integer names and those that are inherited.

Because the order of iteration is implementation dependent, iterating over an array may not visit elements in a consistent order. Therefore it is better to use a for loop with a numeric index (or Array.forEach or the non-standard for...of loop) when iterating over arrays where the order of access is important.

If new properties are added to the object being enumerated during enumeration, the newly added properties are not guaranteed to be visited in the active enumeration. A property name must not be visited more than once in any enumeration.

Let's talk about with example, if we are using a library, which uses.

Array.prototype.maxLimit = 100000;

This property iterate over the for .. in loop .

Another version of your code to explain for .. in loop

var foo = [3,4,5];

for ( var i in ( alert( JSON.stringify(foo)) || foo ) ) {

    if ( i == 1 ) {
       foo.unshift(6,6);
    }
    console.log('item: '+foo[i] , i , foo.length );    
}

The alert popup only once

1 Comment

The alert pops up only once because the expression in the iteration statement (i.e. the bit in brackets after the in operator) is only evaluated once. The result of the alert expression on the LHS of the || is the undefined value, which evaluates as false, so foo is passed to the operator. I don't see how that makes things clearer to the OP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.