35

Why does Math.min([]) evaluate to 0?

I would expect that it would evaluate to NaN since MDN's manpage for Math.min states "If at least one of the arguments cannot be converted to a number, NaN is returned."

So I guess the refined question is why does [] coerce to 0? Especially considering that [] is truthy (i.e. !![] === true) and Math.min(true) === 1. I am thinking about this wrong?

Tested on Node v7.0.0

jtpeterson
  • 592
  • 5
  • 9
  • 3
    an empty array can be converted to a number tho.... the number being zero.. – I wrestled a bear once. Jan 11 '17 at 21:51
  • https://jsfiddle.net/xq3185ym/ – I wrestled a bear once. Jan 11 '17 at 21:52
  • 2
    ...because the spec says so. – zzzzBov Jan 11 '17 at 21:53
  • https://www.sitepoint.com/javascript-truthy-falsy/ – ppasler Jan 11 '17 at 21:54
  • 5
    I _think_ this is because `[].toString()` yields `""` and the specification says that converting `""` to a number yields `0`. – Andrew Whitaker Jan 11 '17 at 21:55
  • wow... you're right. is this legacy behavior kept for the sake of backwards compatibility or is there a use? – jtpeterson Jan 11 '17 at 21:57
  • 4
    @jtpeterson How would such a thing be useful? Implicit and unintuitive conversions in JavaScript is a root of all hell. And yes, it will stay forever due to backwards compatibility. – freakish Jan 11 '17 at 21:58
  • 1
    @freakish: there's a couple rules that are not all that complicated really, sorry it confuses you. – dandavis Jan 11 '17 at 22:02
  • @freakish, actually it's quite useful to be able to pass objects that can be implicitly converted to numbers or strings for functional programming algorithms. Implicit conversion is a tool, like a screwdriver. If your problem requires a nail, the tool isn't helpful, but this is neither bad nor evil. It's up to the developer to determine what tools are appropriate to use. – zzzzBov Jan 11 '17 at 22:07
  • 2
    @zzzzBov Languages are there to make coders life easier. Assembly is also a screwdriver. But I assure you that it is not fun using this tool. You do it when you have to. The same thing is with JavaScript IMO. You use it cause you have to. You say that these conversions are useful. First of all I have no idea how this is related to functional programming. Secondly I strongly believe in "explicit is better then implicit". I would really like to see real code that uses these kind of implicit conversions and is easy to maintain, understand, extend. – freakish Jan 11 '17 at 22:19
  • @dandavis I think you are confused. Where did I say that these rules are complicated or not? Rule "let's cast everything to string `xyz`" is also very simple, unintuitive and useless. – freakish Jan 11 '17 at 22:19
  • My previous question about the usefulness of this particular coercion isn't really relevant now that I understand it more thoroughly. "The default hint for all objects is string" really pulled the curtain back for me. ... it's converted to a string before being converted to a number. Thanks for your input everyone. – jtpeterson Jan 11 '17 at 22:28

2 Answers2

36

Why does Math.min([]) evaluate to 0?

Because the spec says so:

Math.min casts each parameter to a number using...

ToNumber casts objects to a number using...

ToPrimitive casts objects to primitive values using...

[[Default Value]] internal method converts objects to primitives based on their hint parameter.

The default hint for all objects is string. Which means the array gets converted to a string, which for [] is "".

ToNumber then converts "" to 0, per the documented algorithm

Math.min then takes the only parameter and returns it, per its algorithm.

zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • 2
    Ahhh... hence why only an array of length 0 or 1 will coerce and something like `Math.min([1,42])` will result in `NaN` – jtpeterson Jan 11 '17 at 22:11
16

This happens because [] is coerced to 0.

You can see this with the following call:

(new Number([])).valueOf(); // 0

Therefore, calling Math.min([]) is the same as calling Math.min(0) which gives 0.


I believe that the reason that new Number([]) treats [] as 0 is because:

  1. The spec for the Number(value) constructor uses a ToNumber function.
  2. The spec for the ToNumber(value) function says to use ToPrimitive for an object type (which an array is).
  3. The primitive value of an array is equal to having the array joined, e.g. [] becomes "", [0] becomes "0" and [0, 1] becomes "0,1".
  4. The number constructor therefore converts [] into "" which is then parsed as 0.

The above behaviour is the reason that an array with one or two numbers inside it can be passed into Math.min(...), but an array of more cannot:

  • Math.min([]) is equal to Math.min("") or Math.min(0)
  • Math.min([1]) is equal to Math.min("1") or Math.min(1)
  • Math.min([1, 2]) is equal to Math.min("1,2") which cannot be converted to a number.
James Monger
  • 10,181
  • 7
  • 62
  • 98
  • 3
    The original question acknowledges this: *"So I guess the refined question is why does [] coerce to 0"*. I think the OP wants to know why this coercion occurs. – Andrew Whitaker Jan 11 '17 at 21:57
  • 1
    Thanks. Array of length 0 or 1 will coerce to a number. Go figure. Here's a link with a useful table at the bottom with more oddities: http://www.w3schools.com/js/js_type_conversion.asp – jtpeterson Jan 11 '17 at 22:00