Since I started working with JS, I've thought the only way to invoke a function on a number literal is to put it in expression position by wrapping it with parens, like so:
1.toString();
// SyntaxError: identifier starts immediately after numeric literal
(1).toString();
// "1"
Today, it occurred to me to try this:
0.1.toString();
// "0.1"
Why does this work? A pointer into the official spec would be great.
Edit Ambiguity was my first thought, but then decided that there's no ambiguity in 1.toString()
either. It's deeper than I first thought, but I still think I'm right. Here's why:
Property names can begin with digits
var obj = { "1" : 1, "2" : 2 };
Property names that begin with digits can only be referenced with square brackets
obj.1;
// SyntaxError: Unexpected token ILLEGAL
obj['1'];
// 1
Also:
1['toString']();
// '1'
Therefore, 1.
followed by any non-digit will always be a method call or property access, never a decimal number. Likewise, 1.
followed by any digit will always be a decimal number, never a method call or property access.
Once it's seen the first .
in 0.1
, then a subsequent .
cannot be part of the number.
It's all about ambiguity.
edit — section 7.8.3 of the spec explicitly insists on this:
The source character immediately following a NumericLiteral must not be an IdentifierStart or DecimalDigit.
I'm not sure exactly what that's trying to prevent, but the JavaScript lexer is pretty gnarly, mostly thanks to the regex literal grammar and the need for a weird parser-lexer hack to deal with that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With