JS Quirks: stringified numbers
When I was working on Node.js PR 9492, this comment
This should probably test for a wider range of values.
test/parallel/test-net-internal.js
has some good examples.
made me look at that file. As I was going through the test, few of the bad values were interesting. I normally test with stringified positive decimal numbers and negative decimal numbers. But I saw stringified negative octal, binary, and hexa decimal numbers.
const bad = [-1, 'a', {}, [], false, true, 0xFFFF + 1, Infinity,
-Infinity, NaN, undefined, null, '', ' ', 1.1, '0x',
'-0x1', '-0o1', '-0b1', '0o', '0b'];
I got curious as I have never used them before, I just wanted to see their corresponding negative values. So I wrote a program like this
[-0x1, '-0x1', -0o1, '-0o1', -0b1, '-0b1'].forEach(item => console.log(item, +item));
and I was expecting to see the result
-1 -1
-0x1 -1
-1 -1
-0o1 -1
-1 -1
-0b1 -1
but all I got was
-1 -1
-0x1 NaN
-1 -1
-0o1 NaN
-1 -1
-0b1 NaN
The unary - operator simply negates the magnitude of the numbers. The stringified numbers were not processed in the same way as their number counterparts. So I looked at the ECMAScript specification’s ToNumber Applied to the String Type section (which is actually responsible for converting strings to numbers).
StrNumericLiteral :::
StrDecimalLiteral
BinaryIntegerLiteral
OctalIntegerLiteral
HexIntegerLiteral
...
...
StrDecimalLiteral :::
StrUnsignedDecimalLiteral
+ StrUnsignedDecimalLiteral
- StrUnsignedDecimalLiteral
Only the StrDecimalLiteral
production allows signed numbers. If we look at the definition of others in the Numeric Literals section,
BinaryIntegerLiteral ::
0b BinaryDigits
0B BinaryDigits
BinaryDigits ::
BinaryDigit
BinaryDigits BinaryDigit
BinaryDigit :: one of
0 1
OctalIntegerLiteral ::
0o OctalDigits
0O OctalDigits
OctalDigits ::
OctalDigit
OctalDigits OctalDigit
OctalDigit :: one of
0 1 2 3 4 5 6 7
HexIntegerLiteral ::
0x HexDigits
0X HexDigits
HexDigits ::
HexDigit
HexDigits HexDigit
HexDigit :: one of
0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
So, as per the specification, only the decimal numbers can have signs in the stringified number form. That is why the others are not considered as numbers.