9

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 ?

8
  • 1
    developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… @FelixKling Commented May 11, 2016 at 1:19
  • 1
    Yes, MDN is wrong. It's also conflating all the different ... use cases. Commented May 11, 2016 at 1:19
  • 1
    Could you write down where to find the right documents, so let others know. @FelixKling Commented May 11, 2016 at 1:22
  • 2
    @WeiWang: I haven't found a great source yet, except for the spec (which is not necessarily straightforward to understand). I'd love to update the MDN article, but I'm not that familiar with the editing tools (e.g. how the articles are categorized). Maybe I should just write a blog post myself. Why I think it's important that people don't mistake the ... as an operator: stackoverflow.com/q/35019557/218196 . Commented May 11, 2016 at 1:34
  • 2
    @choz: In theory I have a blog... with 10 blog posts the last one from 5 years ago or so :D Commented May 11, 2016 at 2:15

3 Answers 3

14

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:

enter image description here

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.

Sign up to request clarification or add additional context in comments.

2 Comments

This Answer could be canonical as relating to spread element. Or perhaps a new canonical as to the spread element? Have not read that term previously
Note, not that good, here, at asking Questions. stackoverflow.com/questions/37151966/… . Please advise if Question should be updated to include more details
3

Array

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);

Spread operator

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()

4 Comments

Could you explain what is going on here.
Or shorter: Array.from(Array(3), ()=>1);
You didn't explain why the first case didn't work as the OP expected even though the length was set to 3.
@guest271314: Regarding the comment you deleted: I'm conflicted. On one side I understand that it makes sense to simplify what ... does exactly, on the other hand, it may give people a wrong impression.
0

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.

4 Comments

"Therefore, map does not know where to start iterating your array from." Well, it could start at 0 ;)
@FelixKling It'd say 'Which one is 0'? :)
Well, array[Symbol.iterator]() also manages to iterate over the array without problems (it will simply return undefined for holes). I'm sure there are valid reasons why .map skip holes, but it's definitely not a technical limitation.
@FelixKling I believe that array in js has their own indexing methods which makes them iterable. E.g. var x = []; x[5] = 1; will make your so called holes from its index 0 to 4. It's quite interesting why MDN doesn't provide this information.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.