29

I'm trying to set default values on an uninitialized array using the map function but it doesn't seem to work, any ideas on how to set default values?

Consider this code snippet I tried in Chrome console.

> var N = 10;
> var x = new Array(N);
> x
  [undefined x 10]

> x.map(function(i) { return 0;});
  [undefined x 10]

I was expecting the array to be initialized to 0's.

Raja
  • 6,354
  • 9
  • 30
  • 34

8 Answers8

31

If you'd like to fill an array, you can use Array(5).fill() and the methods will then work as expected--see the alternate related answer from aasha7. Older pre-fill approaches include:

Array.apply(null, new Array(5)).map(function() { return 0; });
// [ 0, 0, 0, 0, 0 ]

After some reading one of the posts linked in the comments, I found this can also be written as

Array.apply(null, {length: 5}).map(function() { return 0; });

However, trying to use .map on undefined values will not work.

x = new Array(10);
x.map(function() { console.log("hello"); });

// so sad, no "hello"
// [ , , , , , , , , ,  ]

.map will skip over undefined values :(

jimmont
  • 2,304
  • 1
  • 27
  • 29
maček
  • 76,434
  • 37
  • 167
  • 198
  • 5
    +1; the problem here is that `map` skips *indexes* that have never been assigned a value. Compare `Object.keys(new Array(2))` (no enumerable properties) to `Object.keys([undefined, undefined])` (two enumerable properties, `0` and `1`). In the first case, the array has no values assigned to any indexes; in the second case, the indexes `0` and `1` have been assigned the value `undefined`. – apsillers Dec 02 '13 at 17:16
  • 1
    @apsillers, you are correct. To clarify, `var x = new Array(5);` just has `x.length == 5` and the `Array.prototype`. Aside from that, no enumerable keys are set. – maček Dec 02 '13 at 17:22
  • very cool trick - I'm still trying to understand what is the difference between "new Array(5)" vs "Array.apply(null, new Array(5))" – Raja Dec 02 '13 at 17:23
  • 1
    @Raja you should totally check out [Ziraks explanation on this](http://stackoverflow.com/a/18949651/1487756) – Moritz Roessler Dec 02 '13 at 17:25
  • I ran into this problem and it actually _does_ work on `undefined` values, (undefined as in the javascript type), just not on uninitialized values. – Frido Emans May 29 '20 at 14:14
  • map does not skip over undefined values, see: `[undefined].map(() => {console.log('ayo')}`. It's because Array(5) creates an array with 5 **empty** slots, not 5 undefined values. See answer here https://stackoverflow.com/questions/66449263/javascript-spread-with-array/66449468#66449468 – Nick Mar 03 '21 at 01:40
14

I'd just like to point out that you can now do:

Array(2).fill().map(_ => 4);

This will return [4, 4].

aashah7
  • 2,075
  • 1
  • 17
  • 24
3

That's how it's described by the ECMAScript Language specification

Here's the relevant part of Array.prototype.map, as described by (§15.4.4.19)

  • ...
  • 8. Repeat, while k < len
    • a) Let Pk be ToString(k).
    • b) Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
    • c) If kPresent is true, then
      • do the magic
  • ...

Since there is no initilized member in your array, calling e.g new Array (1337).hasOwnProperty (42)evaluates to false, hence the condition in step 8.c is not met.

You can however use a little "hack" to do what you want.

Array.apply(null, { length: 5 }).map(Number.call, Number) //[0, 1, 2, 3, 4]

How this works has been thouroughly explained by @Zirak

Community
  • 1
  • 1
Moritz Roessler
  • 8,542
  • 26
  • 51
2

Also possible solution without Array.prototype.fill:

[...Array(10)].map((_, idx) => idx); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
AlexanderFSP
  • 652
  • 4
  • 10
1

The .map() function skips entries that have never been assigned values. Thus on a newly-constructed array like yours, it does essentially nothing.

Here is the MDN description.

Pointy
  • 405,095
  • 59
  • 585
  • 614
1

With .map(), undefined elements are skipped and not passed to the callback so if you have an array with no elements that actually contain anything, then the callback is never called.

From the ECMA script 262, 5.1 specification, section 15.4.4.19:

callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

You can populate an array with zeros using this function:

function fillArrayWithNumber(n) {
  var arr = Array.apply(null, Array(n));
  return arr.map(function (x, i) { return 0; });
}

fillArrayWithNumber(5); // [0,0,0,0,0]

Or with a small change you can use indexes instead:

function fillArrayWithIndex(n) {
  var arr = Array.apply(null, Array(n));
  return arr.map(function (x, i) { return i; });
}

fillArrayWithIndex(5); // [0,1,2,3,4]

Fiddle

Andy
  • 61,948
  • 13
  • 68
  • 95
1

Building on a previous answer there is new shorter syntax. The OP wanted to create an array of N items initialized with 0.

var N = 10;
var x = new Array(N).fill(0);
// x is now: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]

You also don't need the new - it's optional in this context.

Check the compatibility of your target platform and/or use a pollyfill if not available.

Guy
  • 65,082
  • 97
  • 254
  • 325