Also you can try .map() method instead of for..loop.
While map() doesn't call the iteratee on holes it does preserve the holes in the array it returns. The point being - the use case for map() (producing a new array of identical length containing transformed values) is much narrower than that of a for…loop. The behaviour of map() is consistent with treating holes as None while values are treated as Some(value). This is problematic when one needs to replace the holes with some default value - in that case it is necessary to use Array.from():
Ultimately the entire for…loopconsidered harmful attitude is misguided. Iteration is often required without arrays being involved. So it is valuable to be able to write a readable for…loop.
Higher order functions (HOFs) like reduce(), map() and filter() have their uses but forEach() is the oddball as it needs a function with side effects to be useful.
Iteration on iterables doesn't have direct access to the Array HOFs, so either they need to be converted to intermediate arrays (e.g. with Array.from()) or be processed with for…of.
This works in JavaScript but JavaScript isn't a functional language - and none of today's JavaScript engines support tail call elimination, so recursion is usually avoided to avoid blowing the call stack (and sometimes to avoid the overhead of the function calls).
The fundamental means of iteration in JavaScript is the for…loop which means that mutation of the looping state is essential but the rest of the values can largely be immutable:
constlength=1000000;letstart=performance.now();consta=newArray(length);letfinish=performance.now();console.log(`Sparse array was created in ${finish-start}ms`);// < 5msstart=performance.now();constb=Array.from({length});finish=performance.now();console.log(`Dense array was created in ${finish-start}ms`);// ~60msstart=performance.now();constc=[];c[length-1]=1;finish=performance.now();console.log(`Element added in ${finish-start}ms`);// < 1msconsole.log(c[length-1]);// 1console.log(c.length);// 1000000
Basically think of arrays as key-value stores that use positive integers as keys.
The problem is that JavaScript engines optimize arrays for performance
PACKED (dense) arrays can transition to HOLEY (sparse) arrays - but not the other way around
PACKED processing is more optimized, though:
the performance difference between accessing holey or packed arrays is usually too small to matter or even be measurable.
That said (as already suggested elsewhere), if holes don't have any particular meaning within the processing context, it's better to sanitize HOLEY arrays into PACKED arrays rather than relying on the "skipping behaviour" of select methods.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
The idiomatic way to detect holes in arrays is with the in operator;
If you need to be paranoid about third party libraries modifying prototype objects:
For a more detailed discussion of holes see ECMAScript 6: holes in Arrays.
While
map()doesn't call the iteratee on holes it does preserve the holes in the array it returns. The point being - the use case formap()(producing a new array of identical length containing transformed values) is much narrower than that of afor…loop. The behaviour ofmap()is consistent with treating holes asNonewhile values are treated asSome(value). This is problematic when one needs to replace the holes with some default value - in that case it is necessary to use Array.from():Ultimately the entire
for…loopconsidered harmful attitude is misguided. Iteration is often required without arrays being involved. So it is valuable to be able to write a readablefor…loop.Higher order functions (HOFs) like
reduce(),map()andfilter()have their uses butforEach()is the oddball as it needs a function with side effects to be useful.Iteration on iterables doesn't have direct access to the Array HOFs, so either they need to be converted to intermediate arrays (e.g. with
Array.from()) or be processed with for…of.forEach()exists on Maps, Sets, DOMtokenList, NodeList, TypedArray, etc.But I fail to see the advantage of
over
or perhaps
Perhaps the real solution is to clean up the loop bodies of
for…loopso that they are easier to read.In functional languages recursion is used as the fundamental means of any iteration:
This works in JavaScript but JavaScript isn't a functional language - and none of today's JavaScript engines support tail call elimination, so recursion is usually avoided to avoid blowing the call stack (and sometimes to avoid the overhead of the function calls).
The fundamental means of iteration in JavaScript is the
for…loopwhich means that mutation of the looping state is essential but the rest of the values can largely be immutable:i.e. for a cleaner loop body:
The idea is to organize the top of the loop body so that it could be easily refactored to:
but to then leave the loop body "as is" because it already is sufficiently cleaned up.
Basically think of arrays as key-value stores that use positive integers as keys.
The problem is that JavaScript engines optimize arrays for performance
v8.dev: Elements kinds in V8:
PACKED_SMI_ELEMENTS->HOLEY_SMI_ELEMENTSPACKED_DOUBLE_ELEMENTS->HOLEY_DOUBLE_ELEMENTSPACKED_ELEMENTS->HOLEY_ELEMENTS.PACKED(dense) arrays can transition toHOLEY(sparse) arrays - but not the other way aroundPACKEDprocessing is more optimized, though:That said (as already suggested elsewhere), if holes don't have any particular meaning within the processing context, it's better to sanitize
HOLEYarrays intoPACKEDarrays rather than relying on the "skipping behaviour" of select methods.