Sto cercando di chiamare funzioni letterali, ma ho un comportamento strano.
Considera questo codice che restituisce true
.
23 === (23)
Quando scrivo, prova quanto segue.
(23).toFixed(2)
Ottengo il risultato previsto _23.00_
ma quando provo 23.toFixed(2)
ottengo questo errore.
SyntaxError: Token imprevisto ILLEGAL
In che modo JavaScript valuta le espressioni che non riescono a capirlo e perché ottengo questo errore?
Le risposte di Greg Hewgill e icktoofay sono corrette in tutti i modi, tuttavia, mi piacerebbe scendere un po ‘, astrazione-saggio: vediamo cosa sta realmente accadendo secondo le specifiche javascript.
La sezione 7.8.3 della specifica definisce valori letterali numerici. Possiamo vedere quanto segue:
DecimalLiteral :: DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt) . DecimalDigits ExponentPart(opt) DecimalIntegerLiteral ExponentPart(opt) DecimalIntegerLiteral :: 0 NonZeroDigit DecimalDigits(opt)
Un DecimalLiteral
, un numero, è un gruppo di cifre decimali, eventualmente seguito da un punto, che è probabilmente seguito da altre cifre (tutte possono essere seguite da un esponente, ad esempio e12
). In altre parole, 42.
è legale e uguale a 42
e 3e2
è uguale a 300
.
Nota come se abbiamo un punto, o ci aspettiamo che sia seguito da più cifre / esponente, o che non venga seguito da nulla. Tuttavia, e questa è la parte importante, il punto è parte del numero . Ricorda questo mentre ci spostiamo per osservare come viene obj.prop
l’operatore punto, obj.prop
.
La sezione 11.2.1, Accessori proprietà descrive la notazione punto e parentesi per l’accesso membro:
MemberExpression . IdentifierName
CallExpression
è per chiamate di funzione, che non ci interessa. Notate come ci aspettiamo un MemberExpression
(che può essere un DecimalLiteral
– ma non DecimalLiteral
, guardate e vedete se ho ragione).
Vedi quel puntino? È logico saltare in avanti e dire “beh, c’è un punto nello schema qui … e c’è un punto in 4.foo
… quindi perché c’è un errore?” Purtroppo il mio ipotetico amico che uso per queste frasi, hai dimenticato come appare il DecimalLiteral
! Andiamo oltre due esempi e vediamo cosa succede.
42.foo ^
Il punto di riferimento rappresenta il personaggio su cui ci troviamo. Finora, siamo all’interno di DecimalLiteral / DecimalIntegerLiteral / NonZeroDigit
(che è piuttosto un boccone). Passiamo al prossimo personaggio:
42.foo ^
Ancora parte del numero, un DecimalDigit
perfettamente valido.
42.foo ^
ok, quindi siamo fuori dalla parte DecimalIntegerLiteral
. Ecco lo stesso diagramma sullo schema:
DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt) ^
Quindi siamo su un punto, che è una parte perfettamente valida di un numero. Ora lo consumiamo, come parte del numero , e passiamo a:
42.foo ^
f
non fa parte né di DecimalDigits
né di ExponentPart
, siamo fuori dal numero adesso. Così quello che ora? Cos’è quella f
? Non fa parte di niente. Forse è un accessorio di proprietà? Diamo un’occhiata allo schema:
MemberExpression . IdentifierName ^
Siamo decisamente su MemberExpression
, ma non abbiamo un punto che lo segue: quel punto è già parte del numero. Abbiamo raggiunto un errore sintattico: interrompiamo l’esecuzione e la gettiamo. Spero che tu non viva in una casa di vetro.
Spero che ora capiate perché 42..foo
funziona. Una volta usciti da MemberExpression
, affrontiamo un altro punto:
42..foo ^ MemberExpression . IdentifierName ^
Seguito da un IdentifierName
perfettamente legale.
Naturalmente, ci sono molti altri modi per separare il punto dal numero. Un modo, come hai mostrato, è racchiudere il letterale tra parentesi: (42).foo
. Quando abbiamo raggiunto la fine delle parentesi, siamo fuori da MemberExpression
e in punto. Un altro modo è inserire uno spazio: 42 .foo
, poiché uno spazio non può far parte del numero ed è neutro per il parser, quindi non genera un errore.
A differenza di Ruby (ad esempio), il parser Javascript considera a .
seguenti cifre per far parte del numero. Quindi il parser vede i token:
23.
toFixed
(
2
)
che è un errore di syntax, perché la parola toFixed
segue immediatamente un numero in virgola mobile non ha senso. Una lingua come Ruby che accetta questa syntax vedrebbe i seguenti token:
23
.
toFixed
(
2
)
Prendere in considerazione:
5.
È il valore letterale a virgola mobile o un numero intero 5
seguito da un punto? Non lo sai; è ambiguo. JavaScript prende la precedente vista. Nella vista di JavaScript, hai un letterale a virgola mobile seguito da un identificatore (seguito da parentesi sinistra, numero e parentesi destra).
Alcune persone aggirano questo problema usando due punti:
23..toFixed(2)
Poiché un letterale a virgola mobile può avere solo un punto decimale, l’altro punto è un token punto letterale.