1

Reading this question I tried to perform a modification to the code that creates an array filled with zeroes:

Array.apply(null, Array(10)).map(Number.prototype.valueOf,0);

Instead of this, I wanted to use fill and understand in a better way the usage of the map function in Javascript. Using the developer tools in Chrome I executed the following, getting an error:

Array.apply(null, Array(10)).fill(0).map(Number.prototype.valueOf);

Uncaught TypeError: Number.prototype.valueOf is not generic

As I understand the map function, it executes the callback on each value of the array using that value as argument. The array is correctly created using Array.apply(null, Array(10)).fill(0), so it should be executing Number.prototype.valueOf(0), why is it giving then the error?

Community
  • 1
  • 1
Javier Cabero
  • 118
  • 1
  • 12

3 Answers3

2

So it should be executing Number.prototype.valueOf(0), why is it giving then the error?

No. The map callback is called with no (undefined) this argument if you don't pass one to map, and the array element, the index, and the array as arguments. So it actually calls

Number.prototype.valueOf.call(undefined, 0, 0, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

But valueOf must be invoked on numbers or Number instances, otherwise it will throw.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Ok, I see that Number.prototype.valueOf is not a function that you use with a parameter but as an instance function of the Number class to retrieve the primitive value. Using `Array.apply(null, Array(10)).fill(0).map(a => a.valueOf());` performs as expected. Thanks!! – Javier Cabero Jul 31 '16 at 12:03
2

According to MDN, the map method accepts two parameters, the second one is Value to use as this when executing callback. So when you call:

Array.apply(null, Array(10)).map(Number.prototype.valueOf,0);

You actually call Number.prototype.valueOf.call(0) which always return 0. As you know, if map accept a function that is always return 0, it creates an array filled with 0.

And if you remove the second parameter as below:

Array.apply(null, Array(10)).map(Number.prototype.valueOf);

It throws:

Uncaught TypeError: Number.prototype.valueOf is not generic(...)

You may figure out what the default this is for map in your environment:

[0].map(v=>{console.log(this);}) // =>Window for chrome developer tools

So try this:

Number.prototype.valueOf.call(window)

You may get the same error info.

Zmen Hu
  • 795
  • 3
  • 12
1

The second argument for map is used as this. In the first case, this each time is the number 0 (which is converted to an object Number(0))

Consequently, the map function is calling Number.prototype.valueOf with this being Number(0). This is effectively the same as Number(0).valueOf() , which is naturally the number 0.

(NOT Number.prototype.valueOf(0) - try calling Number.prototype.valueOf(1) and see what that gets you)

Meanwhile, if you don't pass the this argument to map(), then it is set to window. This means you're effectively calling Number.prototype.valueOf on the window. That makes no sense, and so an error is thrown. It doesn't matter that 0 is the argument, because Number.prototype.valueOf() takes no arguments. Number(0).valueOf(1) returns 0 because the argument is ignored completely.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • "*(which is converted to an object `Number(0)`)*" - if you mean `new Number(0)`, then actually no. `this` is not cast to an object in builtin methods. It also is never set to `window`, where would that come from? – Bergi Jul 31 '16 at 11:46
  • @Bergi That's what [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) says... – Niet the Dark Absol Jul 31 '16 at 11:57
  • 1
    And as so often these days, MDN is wrong :-/ I've rolled back [this edit](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map$compare?to=1003361&from=979867). It's always just sloppy mode that lets `this` values in callback functions default to the global object when nothing is passed. – Bergi Jul 31 '16 at 12:23
  • Ah, I see... Fair enough then. – Niet the Dark Absol Jul 31 '16 at 12:53