Given an array, I want to generate its "prefixes", meaning for an array of size N, I want one array containing the first element, an array containing the first two, an array containing the first three, and so on until I get a copy of all N items in the array.
const arr = [1,2,3,4,5]
for (const i in arr) console.log(i, arr.slice(0, i))
// 0, Array []
// 1, Array [ 1 ]
// 2, Array [ 1, 2 ]
// 3, Array(3) [ 1, 2, 3 ]
// 4, Array(4) [ 1, 2, 3, 4 ]
The above is slightly wrong, since at i=0
I want [1]
, and at i=4
I want [1,2,3,4,5]
. So I modified it to use i + 1
, which results in completely unexpected behavior:
for (const i in arr) console.log(i, arr.slice(0, i+1))
// 0, Array [ 1 ]
// 1, Array(5) [ 1, 2, 3, 4, 5 ]
// 2, Array(5) [ 1, 2, 3, 4, 5 ]
// 3, Array(5) [ 1, 2, 3, 4, 5 ]
// 4, Array(5) [ 1, 2, 3, 4, 5 ]
I observed this in the JS console in Firefox, as well as Edge.
Why does it apparently jump straight to an array of length 5 on the second iteration? I confirmed that manually calling arr.slice(0, 3)
returns [1, 2, 3]
as expected, so why does calling it inside the for
loop change the behavior?
3
Answers
Doh, apparently by using the
for-in
construct, thei
value is a String. Soi+1
is01
,11
,21
, ....I guess I'll swap to
for(let i=0; i<arr.length; i++)
Docs for
for..in
state:i is considered as a string. when you do i+1, it will append the 1 on each iteration.
Convert i to numeric and try like below
Using
in
operator for arrays isn’t recommended and widely considered as bad code since it iterates properties of an array (they’re rather strings). The big problem with it also when somebody monkeypatches the prototype likeArray.prototype.myEach = ...
(which is also bad since creates an enumerable property).Just use a number index:
Another option is to use
Array#keys()
to iterate the indexes directly (note that this will be slower than the previousfor
loop since an iterator involved):