20

Was playing around with some code to create an array of 0's and found that for only one value NaN was returned instead of 0. I get this in Chrome, Node, and Firefox.

What's causing the second value to be NaN?

var arr = new Array(32).join(0).split('').map(parseInt)
// prints [0, NaN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
console.dir(arr)
UnknownUnknowns
  • 838
  • 8
  • 17
  • 3
    Have you tried `new Array(32).fill(0);`? –  Sep 01 '15 at 01:52
  • 1
    You may be interested in [Most efficient way to create a zero filled JavaScript array?](http://stackoverflow.com/q/1295584/1529630) – Oriol Sep 01 '15 at 02:08

3 Answers3

26

That's because the function passed to map will be called with three arguments:

  1. The current array item
  2. The index of that item
  3. The whole array

In this case, that function is parseInt, which only uses two arguments:

  1. The string to be parsed
  2. The radix used to parse the string
  3. Additional arguments will be ignored.

Therefore, for the 2nd item in the array (i.e. index 1), the call will be

parseInt("0", 1, ignoredArray)

When the radix is 1, NaN is returned:

  • Let R = ToInt32(radix).
  • If R ≠ 0, then
    • If R < 2 or R > 36, then return NaN.

Also note that if you used a bigger number like new Array(99), you would have seen NaNs starting at index 37.

Oriol
  • 274,082
  • 63
  • 437
  • 513
9

The .map() function passes three arguments to the callback of which two are used by parseInt(): the value, and the index (the third is the array itself). When the index is 1, any string of digits will be an invalid value. The parseInt() function ignores the second argument when it's 0.

To elaborate: for the first element, parseInt() is called like this:

parseInt("0", 0)

because the array value is zero and the index is zero. On the second call, it's this:

parseInt("0", 1)

and that returns NaN.

Note that if you're not too picky about the results being all integers, you can do what you're trying to do with the Number constructor:

var arr = new Array(32).join(0).split('').map(Number);

In ES2015 (the newest ratified standard for JavaScript, which if we are all very good will be fully implemented in all browsers as our Christmas present) you can use the .fill() function:

var arr = new Array(31).fill(0);
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • 6
    [**Three** arguments](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), the third being the array you're mapping over. `parseInt` ignores the third one. – user2357112 Sep 01 '15 at 01:53
  • @user2357112 yes that's true, and yes `parseInt` only looks at its first two arguments. – Pointy Sep 01 '15 at 01:54
7

The mapping passes three arguments to its function:

  • the element;
  • the index of that element within the array; and
  • the array itself.

The parseInt function will look at the first two of those, treating the first correctly as the string but treating the second as the base to use. When the base is neither zero nor in the inclusive range 2..36, it returns NaN (1). If you had an array with forty elements, you'd also see a bunch of NaN values at the end:

0, NaN, 0, 0, 0, ... 0, 0, 0, NaN, NaN

You'd also get some pretty strange results if the number strings were anything other than zero, since the array index would dictate what base was used to interpret it.

To actually fix this, you can just provide a function that will translate what map gives you to what parseInt expects (a map map, I guess you could call it):

function myParseInt(s,r,a) { return parseInt(s,10); }
var arr = new Array(32).join(0).split('').map(myParseInt)
alert(arr)

You might also want to have a look at the way you're creating this array, it will actually end up as an array of size 31 rather than 32. If you just want an array of '0' characters, you can just use:

var arr = new Array(32).fill('0')

assuming you have a browser that supports ECMAScript 2015, which is Safari, Firefox and Chrome-desktop as of the time of this answer.


(1) A base of zero is the default case for handling things like hex prefixes.

A base of one makes no sense in a purely positional system (where each digit is multiplied by a power of the base and accumulated) since the only allowed digit there would be 0, so each place value would be that zero multiplied by 1n. In other words, the only number possible in a base-one system would be zero.

Bases from 2 to 36 are therefore more sensible.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • You say base 1 is not feasible because the only number would be `1^n`, in reality base 1 has as many digits as the number (i.e. `30` = `1.......1` thirty times). Operations on base 1 numbers are very long, especially printing a base 1 number may require printing a very large number of ones wich is not very informative. This is of course a convention and there are also theorems that require base 1 to be proven (i.e. a 3 registers machine is turing complete) – CoffeDeveloper Sep 01 '15 at 08:47
  • 1
    @DarioOO, base 1 only has the digit `0` (not `1`), just like base 2 only has `0` and `1`. In a purely positional system, that `0` can *only* ever generate zero because the value from a given position `n` would be `0 x 1^n`. In other words `00000...000` is zero no matter *how* many digits you have. Base 1 may be feasible for a non-positional system however so I'll make it clear that's what I meant. – paxdiablo Sep 01 '15 at 09:16
  • That's because you extend a definition suited for base2+ numbers, it has been conventionally a number made of 1s not of 0s: https://en.wikipedia.org/wiki/Unary_numeral_system It is not the only definition for a base of a number, there exists general definitions that have unbary base of ones. – CoffeDeveloper Sep 01 '15 at 11:27