8

I tried this


> Array(3)
[ <3 empty items> ]
> // and this joins up all the nothings
> Array(3).join('-')
'--'
> // but...
> Array(3).map((x) => 'a')
[ <3 empty items> ]
> // map doesn't work with the array of empty items!

and I thought I would get the same result as this

> [undefined, undefined, undefined].map((x) => 'a')
[ 'a', 'a', 'a' ]

What's up with that?

6
  • 5
    The .map() method (and others like it) skip uninitialized array positions. Commented Jan 29, 2021 at 13:55
  • 1
    Try Array(3).fill(null).map(x => 'a') Commented Jan 29, 2021 at 13:56
  • 1
    See: Why do I need to copy an array to use a method on it? Commented Jan 29, 2021 at 13:58
  • 1
    Thanks - I couldn't even think how to search for this! Commented Jan 29, 2021 at 14:00
  • yeah so join my be implemented by going through all the indices up to the length and asking for the value, while map is not Commented Jan 29, 2021 at 14:03

3 Answers 3

5

in the first case you creates an array with undefined pointers.

Array(3)

And the second creates an array with pointers to 3 undefined objects, in this case the pointers them self are NOT undefined, only the objects they point to.

[undefined, undefined, undefined]

when we compare the two case it's look like this

//first case look like this 
[undefined, undefined, undefined]
//the second look like this 
 Array(3) [,,,];

map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values. In the first case array values have not explicitly assigned values, whereas in the seconds example were assigned, even if it was the value undefined link

for you example you have to do this

Array(3).fill(undefined).map(x => 'a')
Sign up to request clarification or add additional context in comments.

1 Comment

.fill(undefined) is the same as .fill() since no argument is the same as undefined.
5

you can use :

Array(3).fill(null).map(x => 'a')

5 Comments

This technically is redundant as .fill('a') could be used instead of .fill(null).map(x => 'a')
True, for this specific case .fill('a') would give the same result — but the point here is to demonstrate why .map() doesn’t work on sparse arrays and how to convert them into mappable arrays. Using .fill(null) followed by .map(...) is more general and flexible for arbitrary transformations.
Another technicality is that the argument in .fill(null) could be any value, even nothing as that is the same as undefined in each element.
Yep, that's true — ‍‍‍.fill() with no arguments works too because it fills the array with undefined, making it dense. But the key point of my answer was to explain why .map() doesn't work on sparse arrays, and show how .fill(...) (with any value) solves that problem. I used null just for clarity — it's explicit and helps highlight that we're intentionally filling the array before mapping.
Don't worry, just code golfing this answer.
0

Many array methods skip empty/uninitialized values ("sparse arrays"). Note that empty/uninitialized is a different state than an array entry containing a value undefined or null.

Array(5)                  // [empty × 5]
Array(5).fill(undefined)  // [undefined, undefined, undefined, undefined, undefined]
Array(5).fill(null)       // [null, null, null, null, null]

As other answers point out, you can use fill() to initialize all indices of your array if you want to run an array method like map() across all array indices.

Per MDN...

Array methods have different behaviors when encountering empty slots in sparse arrays. In general, older methods (e.g., forEach) treat empty slots differently from indices that contain undefined.

Methods that have special treatment for empty slots include the following: concat(), copyWithin(), every(), filter(), flat(), flatMap(), forEach(), indexOf(), lastIndexOf(), map(), reduce(), reduceRight(), reverse(), slice(), some(), sort(), and splice(). Iteration methods such as forEach don't visit empty slots at all. Other methods, such as concat, copyWithin, etc., preserve empty slots when doing the copying, so in the end the array is still sparse.

Example from the MDN reduce page...

The example illustrates how reduce treats undefined array values differently from empty/uninitialized values. i.e. the undefined value is not skipped and results in NaN whereas the empty/uninitialized value is skipped.

console.log([1, 2, , 4].reduce((a, b) => a + b)); // 7
console.log([1, 2, undefined, 4].reduce((a, b) => a + b)); // NaN

Comments

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.