Skip to main content
added 186 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
> a              // array with only one item, at index 12
[ <12 empty items>, 1 ]
> a[0]           // appears to have undefined at index 0
undefined
> a[0]=undefined // but if we put an actual undefined there
undefined
> a              // it now looks like this
[ undefined, <11 empty items>, 1 ]
> a
[ <12 empty items>, 1 ]
> a[0]
undefined
> a[0]=undefined
undefined
> a
[ undefined, <11 empty items>, 1 ]
> a              // array with only one item, at index 12
[ <12 empty items>, 1 ]
> a[0]           // appears to have undefined at index 0
undefined
> a[0]=undefined // but if we put an actual undefined there
undefined
> a              // it now looks like this
[ undefined, <11 empty items>, 1 ]
add visual example of sparse array vs array with undefined elements
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182

A note on sparse arrays: an array in JavaScript may not actually store as many items as reported by its length; that reported number is simply one greater than the highest index at which a value is stored. If the array holds fewer elements than indicated by its length, its said to be sparse. For example, it's perfectly legitimate to have an array with items only at indexes 3, 12, and 247; the length of such an array is reported as 248, though it is only actually storing 3 values. If you try to access an item at any other index, the array will appear to have the undefined value there, but the array is nonetheless is distinct from one that actually has undefined values stored. You can see this difference in a number of ways, for example in the way the Node REPL displays arrays:

> a
[ <12 empty items>, 1 ]
> a[0]
undefined
> a[0]=undefined
undefined
> a
[ undefined, <11 empty items>, 1 ]

So when you want to "loop through" an array, you have a question to answer: do you want to loop over the full range indicated by its length and process undefineds for any missing elements, or do you only want to process the elements actually present? There are plenty of applications for both approaches; it just depends on what you're using the array for.

A note on sparse arrays: an array in JavaScript may not actually store as many items as reported by its length; that reported number is simply one greater than the highest index at which a value is stored. If the array holds fewer elements than indicated by its length, its said to be sparse. For example, it's perfectly legitimate to have an array with items only at indexes 3, 12, and 247; the length of such an array is reported as 248, though it is only actually storing 3 values. If you try to access an item at any other index, the array will appear to have the undefined value there. So when you want to "loop through" an array, you have a question to answer: do you want to loop over the full range indicated by its length and process undefineds for any missing elements, or do you only want to process the elements actually present? There are plenty of applications for both approaches; it just depends on what you're using the array for.

A note on sparse arrays: an array in JavaScript may not actually store as many items as reported by its length; that number is simply one greater than the highest index at which a value is stored. If the array holds fewer elements than indicated by its length, its said to be sparse. For example, it's perfectly legitimate to have an array with items only at indexes 3, 12, and 247; the length of such an array is 248, though it is only actually storing 3 values. If you try to access an item at any other index, the array will appear to have the undefined value there, but the array is nonetheless is distinct from one that actually has undefined values stored. You can see this difference in a number of ways, for example in the way the Node REPL displays arrays:

> a
[ <12 empty items>, 1 ]
> a[0]
undefined
> a[0]=undefined
undefined
> a
[ undefined, <11 empty items>, 1 ]

So when you want to "loop through" an array, you have a question to answer: do you want to loop over the full range indicated by its length and process undefineds for any missing elements, or do you only want to process the elements actually present? There are plenty of applications for both approaches; it just depends on what you're using the array for.

deleted 22 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182

You can of course use an arrow function if your implementation supports ES6+:

myStringArray.forEach( s => { 
     // ... do something with s ...
} );

Unlike for...of, .forEach only calls the function for elements that are actually present in the array. If passed our hypothetical array with three elements and a length of 248, it will only call the function three times, not 248 times. It also distinguishes between missing elements and elements that are actually set to undefined; for the latter, it will still call the function, passing undefined as the argument. If this is how you want to handle sparse arrays, .forEach may be the way to go even if your interpreter supports for...of.

One advantage of this approach is that you can choose how to handle sparse arrays; thearrays. The above code will run the body of the loop the full length times, with s set to undefined for any missing elements, just like for..of. If; if you instead want to handle only the actually-present elements of a sparse array, like .forEach, you can add a simple in test on the index:

AssigningDepending on your implementation's optimizations, assigning the length value to the local variable (as opposed to including the full myStringArray.length expression in the loop condition) can make a significant difference in performance since it skips a property lookup each time through; using Rhino on my machine, the speedup is 43%through.

  You may see the length caching done in the loop initialization clause, like this:

myStringArray.forEach( function(s, i) => {
   // ... do something with s and i ...
});

for...of doesn't give you the index associated with each object, but as long as the object you're iterating over is actually an instance of Array (and not one of the other iterable types for..of works for other iterable types which may not have this methodon), you can use the Array#entries method to change it to an array of [index, item] pairs, and then iterate over that:

Unlike for...of, .forEach only calls the function for elements that are actually present in the array. If passed our hypothetical array with three elements and a length of 248, it will only call the function three times, not 248 times. It also distinguishes between missing elements and elements that are actually set to undefined; for the latter, it will still call the function, passing undefined as the argument. If this is how you want to handle sparse arrays, .forEach may be the way to go even if your interpreter supports for...of.

One advantage of this approach is that you can choose how to handle sparse arrays; the above code will run the body of the loop the full length times, with s set to undefined for any missing elements, just like for..of. If you instead want to handle only the actually-present elements of a sparse array, like .forEach, you can add a simple in test on the index:

Assigning the length value to the local variable (as opposed to including the full myStringArray.length expression in the loop condition) can make a significant difference in performance since it skips a property lookup each time through; using Rhino on my machine, the speedup is 43%.

  You may see the length caching done in the loop initialization clause, like this:

myStringArray.forEach( function(s, i) {
   // ... do something with s and i ...
});

for...of doesn't give you the index associated with each object, but as long as the object you're iterating over is actually an Array (for..of works for other iterable types which may not have this method), you can use the Array#entries method to change it to an array of [index, item] pairs, and then iterate over that:

You can of course use an arrow function if your implementation supports ES6+:

myStringArray.forEach( s => { 
     // ... do something with s ...
} );

Unlike for...of, .forEach only calls the function for elements that are actually present in the array. If passed our hypothetical array with three elements and a length of 248, it will only call the function three times, not 248 times. If this is how you want to handle sparse arrays, .forEach may be the way to go even if your interpreter supports for...of.

One advantage of this approach is that you can choose how to handle sparse arrays. The above code will run the body of the loop the full length times, with s set to undefined for any missing elements, just like for..of; if you instead want to handle only the actually-present elements of a sparse array, like .forEach, you can add a simple in test on the index:

Depending on your implementation's optimizations, assigning the length value to the local variable (as opposed to including the full myStringArray.length expression in the loop condition) can make a significant difference in performance since it skips a property lookup each time through. You may see the length caching done in the loop initialization clause, like this:

myStringArray.forEach( (s,i) => {
   // ... do something with s and i ...
});

for...of doesn't give you the index associated with each object, but as long as the object you're iterating over is actually an instance of Array (and not one of the other iterable types for..of works on), you can use the Array#entries method to change it to an array of [index, item] pairs, and then iterate over that:

added 106 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 82 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 5 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
Fix entries example
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 773 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 239 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 17 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 8 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
deleted 18 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 6 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 118 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
Add discussion of sparse arrays and the way they are treated by the different solutions.
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
edited body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 45 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 2 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
edited body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 14 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
deleted 1 character in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 1 character in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
deleted 115 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 3 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading
added 119 characters in body
Source Link
Mark Reed
  • 94.4k
  • 17
  • 141
  • 182
Loading