¿Por qué 0.-5 se evalúa como -5?

84

Supongamos que yo escribo 0.5como 0.-5en forma inesperada, pero todavía puede funcionar. ¿Qué hace 0.in 0.-5para que aún pueda ejecutarse y se evalúe como -5?

También probé alert(0.-5+1)que imprime -4, hace caso omiso de JavaScript 0.en 0.-5?

ocomfd
fuente
55
0.es como 0.0. O simplemente 0.
Ry-
61
¿Qué te hace pensar que 0.-5es una "forma inesperada"?
Nico Haase
15
@NicoHaase: Estoy bastante seguro de que el OP utilizó "forma inesperada" para significar "No tenía la intención / esperaba escribir eso, pero de alguna manera lo hice".
Filip Milovanović
15
Esto también funciona en muchos otros lenguajes (por ejemplo, Python). Personalmente, no me gusta nada. Preferiría haber 0.-5sido un error de sintaxis y no permitir literales flotantes con un período final, pero obligar a las personas a escribir .0al final.
Giacomo Alzetta
9
Es especialmente malo porque permitir que los números terminen en le .impide escribir algo como 123.toString(16)(un truco común es usar 123..toString(16), que es realmente (123.).toString(16))
12Me21

Respuestas:

191

Los dígitos finales después de a .son opcionales:

console.log(0. === 0); // true

Entonces

0.-5

evalúa a

0 - 5

que es justo -5. Similar,

0.-5+1

es

0 - 5 + 1

cual es

-5 + 1

o -4.

CertainPerformance
fuente
16
Los dígitos iniciales también son opcionales, por lo que .0-5 también es válido
icenac
48

0.-5pudo analizar con éxito como 0.[1] , -y 5. A continuación se muestra el árbol de sintaxis abstracto para la expresión generada por AST Explorer:

Árbol de análisis generado por AST Explorer

Esto (de forma inesperada) es JavaScript válido y se evalúa como -5.


[1] De acuerdo con la gramática para literales numéricos, los dígitos decimales y las partes de exponentes son opcionales:

NumericLiteral ::
  DecimalLiteral
  [...]

DecimalLiteral ::
  DecimalIntegerLiteral. DecimalDigits opt ExponentPart opt

Salman A
fuente
¿Cómo extrajo el AST?
Κωλζαρ
8
Vaya a astexplorer.net , elija un idioma y un analizador, pegue el código, elija salida JSON (o simplemente tome una captura de pantalla).
Salman A
39

En JS puede expresar un número con punto decimal opcional.

x = 5.;    //5
x = 5. + 6.   //11

Y a partir del comentario de Tvde1, también se puede aplicar cualquier método numérico.

5..toString()

Esta sintaxis nos permite ejecutar las funciones numéricas sin paréntesis.

5.toString() //error
(5).toString() //good
5..toString() //good
5 .toString() // awesome

Vea esta pregunta para averiguar por qué.

Charlie
fuente
4
Incluso puedes hacerlo 5..toString().
Tvde1
2
De hecho, debe hacer 5..toString () para llamar al método, de lo contrario, debe usar paréntesis: (5) .toString ()
jo_va
3
@PeterMortensen Ruby, por ejemplo. También ALGOL 68. En Common Lisp, por extraño que parezca, 1.0es un punto flotante pero 1.es un número entero.
Sneftel
2
@FlorianF No lo harías, pero eso no significa que el analizador deba tener una mayúscula especial para rechazarlo. floats tienen métodos y 5.es un float.
chepner
2
@MasonWheeler Ciertamente, no es el caso de que cualquier otro idioma donde (1).toMethod()sea ​​legal prohíba (1.)analizar correctamente. El enfoque más tradicional de análisis (lectura codiciosa de tokens, incluidos los literales, y luego análisis) produce el comportamiento de Javascript.
Sneftel
7

Creo que la respuesta real no se trata del punto decimal, sino del signo menos: ¿no se interpretará como un operador si está precedido por algo que parezca un número?

Sean_999
fuente
1
Entonces, al menos desde algún punto de vista, todavía se trata de que el punto decimal se interprete como parte de un número literal; de lo contrario, lo que precedió al signo menos no "parecería un número".
Pac0
5

console.log(0. - 5)      // -5
console.log(0 - 5)       // -5
console.log('0.' - 5)    // -5
console.log('0' - 5)     // -5
console.log(0.-5 === -5) // true

'0.' o '0' es el mismo en JavaScript porque el tipo es único para los números, llamado Número. El operador menos está entre números, intente siempre convertir lo que pasa en un número. En Python es diferente primero es un Float y el segundo un Integer porque tiene varios tipos.

Κωλζαρ
fuente
Este problema no está relacionado con los tipos; solo está relacionado con la sintaxis.
user4642212