Die Antworten von Greg Hewgill und icktoofay sind in jeder Hinsicht korrekt, aber ich möchte etwas abstrahieren: Mal sehen, was wirklich nach der Javascript-Spezifikation passiert.
Section 7.8.3 der Spezifikation definiert numerische Literale. Wir können die folgenden sehen:
DecimalLiteral ::
DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
. DecimalDigits ExponentPart(opt)
DecimalIntegerLiteral ExponentPart(opt)
DecimalIntegerLiteral ::
0
NonZeroDigit DecimalDigits(opt)
A DecimalLiteral
, eine Zahl, ist ein Bündel von Dezimalstellen, möglicherweise gefolgt von einem Punkt, der möglicherweise durch andere Ziffern gefolgt wird (die alle durch einen Exponenten verfolgt werden kann, e12
zum Beispiel). Mit anderen Worten, 42.
ist legal und entspricht 42
und 3e2
entspricht 300
.
Beachten Sie, wenn wir einen Punkt haben, erwarten wir entweder, dass ihm weitere Ziffern/Exponenten folgen oder dass nichts folgt. Jedoch, und das ist der wichtige Teil, der Punkt ist Teil der Nummer. Denken Sie daran, während wir uns bewegen, um zu sehen, wie der Punktoperator obj.prop
behandelt wird.
Section 11.2.1, Property Accessors beschreibt den Punkt und Klammer-Notation für Mitglied Zugang:
MemberExpression . IdentifierName
CallExpression
für Funktionsaufrufe ist, die wir nicht interessieren. Beachten Sie, wie wir eine MemberExpression
erwarten (die eine DecimalLiteral
sein kann - aber nehmen Sie mein Wort dafür nicht, schauen Sie und sehen Sie, ob ich Recht habe).
Sehen Sie diesen kleinen Punkt? Es ist logisch, nach vorne zu springen und zu sagen: "Nun, hier ist ein Punkt im Schema ... und es gibt einen Punkt in 4.foo
... also, warum gibt es einen Fehler?" Leider habe ich meinen hypothetischen Freund, den ich für diese Sätze verwende, vergessen, wie die DecimalLiteral
aussieht! Lassen Sie uns über zwei Beispiele gehen und sehen, was passiert.
42.foo
^
Das Caret repräsentiert den Charakter, auf dem wir uns befinden. Bis jetzt sind wir innerhalb DecimalLiteral/DecimalIntegerLiteral/NonZeroDigit
(das ist ziemlich ein Mundvoll). Lassen Sie sich auf das nächste Zeichen verschieben:
42.foo
^
Noch Teil der Nummer, ein absolut gültigen DecimalDigit
.
42.foo
^
ok, so sind wir aus dem DecimalIntegerLiteral
Teil. Hier ist das gleiche Diagramm auf dem Schema:
DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt)
^
So sind wir auf einem Punkt, der ein perfekt gültiger Teil einer Nummer ist. Jetzt verbrauchen wir es, als Teil der Nummer und bewegen auf:
42.foo
^
f
ist weder Teil DecimalDigits
noch von ExponentPart
sind wir jetzt von der Zahl aus. So was jetzt? Was ist das f
? Es ist nicht Teil von irgendetwas. Vielleicht ist es ein Eigentum Accessor? Schauen wir uns die Regelung einen Blick:
MemberExpression . IdentifierName
^
Wir sind auf jeden Fall auf MemberExpression
, aber wir haben nicht einen Punkt haben, die es folgt -, dass Punkt bereits Teil der Zahl ist. Wir haben einen syntaktischen Fehler erreicht: Wir stoppen die Ausführung und werfen sie. Hoffentlich leben Sie nicht in einem Glashaus.
Hoffentlich verstehen Sie jetzt, warum 42..foo
funktioniert. Sobald wir aus dem MemberExpression
sind, dann stellen wir einen weiteren Punkt:
42..foo
^
MemberExpression . IdentifierName
^
Gefolgt von einem völlig legal IdentifierName
.
Natürlich gibt es mehrere andere Möglichkeiten, den Punkt von der Zahl zu trennen. Ein Weg, wie Sie gezeigt haben, besteht darin, das Literal in Klammern zu umgeben: (42).foo
. Wenn wir das Ende der Klammern erreicht haben, sind wir außerhalb der MemberExpression
, und auf den Punkt.Eine andere Möglichkeit besteht darin, ein Leerzeichen einzufügen: 42 .foo
, da ein Leerzeichen nicht Teil der Nummer sein kann und es für den Parser neutral ist, sodass es keinen Fehler auslöst.
Ausgezeichnete Antwort! –