Reputation: 1328
Trying to allocate new array with values.
Case 1 :
var x = new Array(3).map(()=>1);
Now x
is [undefined * 3]
Case2 :
var x = [...new Array(3)].map(()=>1);
And now x
is [1,1,1]
Can someone help here?
Why using this spread operator makes such a difference?
And why Case 1 doesn't work ?
Upvotes: 9
Views: 1367
Reputation: 17888
Why case 1 doesn't work ?
Map function calls callback function in each element in ascending order
In your first case (breaking down..),
var x = new Array(3);
x = x.map( () => 1 );
x
is an array with uninitialized index. Therefore, map
function does not know where to start iterating your array from. And causing it to not iterating it at all (Which is not working).
You can test it by (in Chrome),
var x = new Array(5);
// This will display '[undefined x 5]' in chrome, because their indexes are uninitialized
x[1] = undefined;
// '[undefined x 1, undefined, undefined x 3]' Only array[1] that has its index.
// And you can use 'map' function to change its value.
x = x.map( () => 1 );
// '[undefined x 1, 1, undefined x 3]'
Why using this spread operator makes such a difference?
In your second sample,
Spread operator allows parts of an array literal to be initialized from an iterable expression
And enclose it in square bracket to properly use it.
So, [...new Array(2)]
is actually an indexed array of [undefined, undefined]
.
Since your array in the following sample has been indexed. Let's have a look (in Chrome),
var x = [...new Array(2)];
// Now 'x' is an array with indexes [undefined, undefined]
x = x.map( () => 1 );
// Will return [1, 1]
Now, each value in x
has its own indexes. Then finally, map
function is able to iterate over it and call the callback function for each element in ascending order.
Upvotes: 0
Reputation: 1
arrayLength
If the only argument passed to the
Array
constructor is an integer between 0 and 232-1 (inclusive), this returns a new JavaScript array with length set to that number.
new Array(3)
does not actually create iterable values at created array having .length
property set to 3
.
See also Undefined values with new Array() in JavaScript .
You can use Array.from()
at first example to return expected results
var x = Array.from(Array(3)).map(()=>1);
The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) or multiple variables (for destructuring assignment) are expected.
var x = [...new Array(10)].map(()=>1);
creates an array having values undefined
and .length
set to 10
from Array(10)
, which is iterable at .map()
Upvotes: 3
Reputation: 816790
tl;dr: The first array has holes, the second one doesn't. .map
skips holes.
By using a spread element, the array is treated as an iterable, i.e. you get an iterator to iterate over the array. The iterator basically works like a for
loop, it will iterate the array from index 0
to index array.length - 1
(see the spec for details), and add the value at each index to the new array. Since your array doesn't contain any values, array[i]
will return undefined
for every index.
That means, [...new Array(3)]
results in an array that literally contains three undefined
values, as opposed to just a "spare" array of length 3
.
See the difference in Chrome:
We call "sparse arrays" also "arrays with holes".
Here is the crux: Many array methods, including .map
, skip holes! They are not treating the hole as the value undefined
, the completely ignore it.
You can easily verify that by putting a console.log
in the .map
callback:
Array(3).map(() => console.log('call me'));
// no output
And that's the reason your first example doesn't work. You have a sparse array with only holes, which .map
ignores. Creating a new array with the spread element creates an array without holes, hence .map
works.
Upvotes: 14