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
.in0.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:
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.