difference between 'for (var i=0; i < x.length; i++)' and 'for (var iin x)'

E

erdibalint

Hi,

I've come across the problem and I spent a remarkable amount of time
debugging at the end of which I found the cause of the bug to be the
following:

var arr = ['a', 'b', 'c', 'd'];
var arr2 = [];
for (var i=0; i < arr.length; i++) {
var elt = arr;
arr2.push(elt);
}
// arr2 equals ["a", "b", "c", "d"]

var arr = ['a', 'b', 'c', 'd'];
var arr2 = [];
for (var i in arr) {
var elt = arr;
arr2.push(elt);
}
// arr2 equals ["a", "b", "c", "d", function()]

I thought that the second type of for loop is identical to the first
one and just adds syntetic sugar. I guess I was wrong, can anyone shed
some light on how the two loops are different?

Thank you,
Bálint
 
R

RobG

erdibalint said:
Hi,

I've come across the problem and I spent a remarkable amount of time
debugging at the end of which I found the cause of the bug to be the
following:

var arr = ['a', 'b', 'c', 'd'];
var arr2 = [];
for (var i=0; i < arr.length; i++) {
var elt = arr;
arr2.push(elt);
}
// arr2 equals ["a", "b", "c", "d"]

var arr = ['a', 'b', 'c', 'd'];
var arr2 = [];
for (var i in arr) {
var elt = arr;
arr2.push(elt);
}
// arr2 equals ["a", "b", "c", "d", function()]

I thought that the second type of for loop is identical to the first
one and just adds syntetic sugar. I guess I was wrong, can anyone shed
some light on how the two loops are different?


"syntactic sugar"?

The first loops over the indexes of arr, from 0 to (arr.length - 1).

The second loops over the enumerable properties of arr, which, for an
unmodified Array and where Array.prototype remains unmodified, will be
those index[1] properties that have been assigned a value.

However, if either the array object itself (arr) or Array.prototype have
been modified with additional properties that aren't indexes, the second
will also loop over those also whereas the first will not.

A for..in loop is typically only used for sparse arrays, i.e. where the
length is large but only a few values have been assigned to some
indexes, where it is significantly faster than iterating over all the
indexes from 0 to length-1.

Some libraries extend Array.prototype and some script authors treat
array objects as "hashes". Both of which may cause for..in loops to do
unexpected things that otherwise they may not.


1. An array index is just a property that has an integer as its property
name, although the index is still a string.
 
E

erdibalint

Thank you for your clear explanation. Synthetic sugar means a simpler
(more concise or easier to retain) form of an expression that does the
same (has the same semantics) as the more complex one.
 
L

Lasse Reichstein Nielsen

Randy Webb said:
Is there any assurance that for-in will give them back to you in any
predictable order? :)

The specification of the for-in statement says:
"The order of enumeration is defined by the object."
A quick scan doesn't show any specification for Array objects.

/L
 
R

RobG

RobG said the following on 2/20/2008 6:49 AM:


erdibalint said:
Hi,
I've come across the problem and I spent a remarkable amount of time
debugging at the end of which I found the cause of the bug to be the
following:
var arr = ['a', 'b', 'c', 'd'];
var arr2 = [];
for (var i=0; i < arr.length; i++) {
var elt = arr;
arr2.push(elt);
}
// arr2 equals ["a", "b", "c", "d"]
var arr = ['a', 'b', 'c', 'd'];
var arr2 = [];
for (var i in arr) {
var elt = arr;
arr2.push(elt);
}
// arr2 equals ["a", "b", "c", "d", function()]
I thought that the second type of for loop is identical to the first
one and just adds syntetic sugar. I guess I was wrong, can anyone shed
some light on how the two loops are different?

"syntactic sugar"?
The first loops over the indexes of arr, from 0 to (arr.length - 1).
The second loops over the enumerable properties of arr, which, for an
unmodified Array and where Array.prototype remains unmodified, will be
those index[1] properties that have been assigned a value.

Is there any assurance that for-in will give them back to you in any
predictable order? :)


No, well spotted.

As Lasse says, the spec doesn't define any particular order so none
should be expected.

There is useful thread here:

<URL:
http://groups.google.com.au/group/c...k=gst&q="for..in"+sort+order#21c3348ba41b2742
 
E

Evertjan.

RobG wrote on 21 feb 2008 in comp.lang.javascript:
No, well spotted.

As Lasse says, the spec doesn't define any particular order so none
should be expected.

There are many applications where the order is not important,
just the manipulation on each object member is:

var a = [1,2,3];
a['large'] = 999;
for (var n in a)
a[n]++;
document.write(a.join('-'));
document.write('<br>');
document.write(a['large']);

shows:

2-3-4
1000

========================

To get some idea of the undocumented predictability of the order:

var a = [];
a.push(1,2,3);
a['large'] = 999;
a.push(4,5,6);
for (var n in a)
document.write(a[n] + ' [' + n + ']<br>');

both IE7 and FF2 show:

1 [0]
2 [1]
3 [2]
999 [large]
4 [3]
5 [4]
6 [5]
 
R

RobG

Evertjan. said:
RobG wrote on 21 feb 2008 in comp.lang.javascript:
No, well spotted.

As Lasse says, the spec doesn't define any particular order so none
should be expected.

There are many applications where the order is not important,
just the manipulation on each object member is: [...]

To get some idea of the undocumented predictability of the order:

To get some idea of the undocumented *un*predictability of the order,
try the following in Firefox:

<div id="xx"></div>
<script type="text/javascript">
function foo(obj) {
var props = {alpha:'alpha', gamma:'gamma',
delta:'delta', beta:'beta'};
for (var p in props) obj[p] = props[p];
var x = [];
for (p in obj){
if (p in props){
x.push(p);
}
}
return x;
}
window.onload = function(){
document.getElementById('xx').innerHTML =
foo(this).join('<br>');
}
</script>
 
E

Evertjan.

RobG wrote on 21 feb 2008 in comp.lang.javascript:
Evertjan. said:
RobG wrote on 21 feb 2008 in comp.lang.javascript:
Is there any assurance that for-in will give them back to you in any
predictable order? :)
No, well spotted.

As Lasse says, the spec doesn't define any particular order so none
should be expected.

There are many applications where the order is not important,
just the manipulation on each object member is: [...]

To get some idea of the undocumented predictability of the order:

To get some idea of the undocumented *un*predictability of the order,
try the following in Firefox:

<div id="xx"></div>
<script type="text/javascript">
function foo(obj) {
var props = {alpha:'alpha', gamma:'gamma',
delta:'delta', beta:'beta'};
for (var p in props) obj[p] = props[p];
var x = [];
for (p in obj){
if (p in props){
x.push(p);
}
}
return x;
}
window.onload = function(){
document.getElementById('xx').innerHTML =
foo(this).join('<br>');
}
</script>

Using the global object inpractical to say the least!

This is only because the global object acts differently in FF by
searching the global object from the end [end = last addded member],
possibly to get a speed bonus. If you change the last code part to:

window.onload = function(){
var q = {};
document.getElementById('xx').innerHTML =
foo(q).join('<br>');
}

.... there is no output difference between IE and FF.

=================================================

btw, please try this in IE and FF to see the real working:

<div id="xx"></div>
<script type="text/javascript">
function foo(obj) {
var props = {alpha:'alpha', beta:'beta',
gamma:'gamma', delta:'delta'};
for (var p in props) obj[p] = props[p];
var x = [];
for (p in obj){
//if (p in props){
x.push(p);
//}
}
return x;
}
window.onload = function(){
document.getElementById('xx').innerHTML =
foo(this).join('<br>');
}
</script>

To see what I mean.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top