2013-09-01 10 views
47

Sto provando a chiamare funzioni letterali, ma ho un comportamento strano.Chiamare la funzione membro del numero letterale

Considerare questo codice che restituisce true.

23 === (23) 

Quando scrivo, prova quanto segue.

(23).toFixed(2) 

ottengo il risultato atteso _23.00_ ma quando provo 23.toFixed(2) ottengo questo errore.

SyntaxError: Unexpected token ILLEGAL

Come si fa a valutare le espressioni JavaScript che non riescono a capire questo e perché ottengo questo errore?

risposta

58

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 in base alle specifiche javascript.

Section 7.8.3 della specifica definisce valori letterali numerici. Possiamo vedere:

DecimalLiteral :: 
    DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt) 
    . DecimalDigits ExponentPart(opt) 
    DecimalIntegerLiteral ExponentPart(opt) 

DecimalIntegerLiteral :: 
    0 
    NonZeroDigit DecimalDigits(opt) 

A DecimalLiteral, un numero, è un gruppo di cifre decimali, eventualmente seguita da un punto, che è seguita eventualmente da altre cifre (ognuno dei quali può essere seguita da un esponente, e12 per esempio). In altre parole, 42. è legale e uguale a 42 e 3e2 equivale a 300.

Nota come se abbiamo un punto, ci aspettiamo che sia seguito da più cifre/esponente, o che non venga seguito da nulla. Tuttavia, e questa è la parte importante, il punto fa parte del numero. Ricorda questo mentre ci spostiamo per osservare come viene gestito l'operatore punto, obj.prop.

Section 11.2.1, Property Accessors descrive il punto e la notazione staffa per l'accesso utente:

MemberExpression . IdentifierName 

CallExpression è per chiamate di funzione, che non ci interessano. Notate come ci aspettiamo un MemberExpression (che può essere un DecimalLiteral - ma non credetemi, guardate e vedete se ho ragione).

Vedere 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 inserimento rappresenta il personaggio su cui ci troviamo. Finora, siamo all'interno di DecimalLiteral/DecimalIntegerLiteral/NonZeroDigit (che è un bel boccone). Passiamo al carattere successivo:

42.foo 
^ 

ancora parte del numero, una perfettamente valido DecimalDigit.

42.foo 
^

ok, così siamo fuori della parte DecimalIntegerLiteral. Ecco lo stesso schema sullo schema:

DecimalIntegerLiteral . DecimalDigits(opt) ExponentPart(opt) 
        ^

Quindi siamo su un punto, che è una parte perfettamente valida di un numero. Ora noi consumiamo, come parte del numero, e andare avanti:

42.foo 
^

f è né parte di DecimalDigitsExponentPart, siamo fuori del numero ora. Così quello che ora? Cos'è quello f? Non fa parte di niente. Forse è un accessorio di proprietà? Diamo uno sguardo al programma:

MemberExpression . IdentifierName 
    ^

Siamo decisamente sulla MemberExpression, ma non abbiamo un punto che lo segue - che 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.

Speriamo che ora comprenda perché lo 42..foo funziona. Una volta che siamo fuori del MemberExpression, ci troviamo di fronte un altro punto:

   42..foo 
       ^
MemberExpression . IdentifierName 
       ^

Seguita da una perfettamente legale IdentifierName.

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 dallo MemberExpression e sul 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.

+1

Ottima risposta! –

35

A differenza di Ruby (ad esempio), il parser Javascript considera un numero . seguito da cifre. Quindi il parser vede i gettoni:

23.toFixed(2)

che è un errore di sintassi, perché la parola toFixed immediatamente a seguito di un numero in virgola mobile non ha senso. Un linguaggio come Ruby che accetta questa sintassi avrebbe visto i seguenti token:

23.toFixed(2)

24

Considerare:

5. 

è che il floating-point letterale 5. o un 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 ovviare a questo utilizzando due punti:

23..toFixed(2) 

Dal momento che una virgola mobile letterale può solo eventualmente avere un punto decimale, l'altro punto è un segno di punti letterale.

+1

'23.0.toFixed (2)' funziona anche – Ehtesham

Problemi correlati