¿Por qué es parseInt (8,3) == NaN y parseInt (16,3) == 1?

191

Estoy leyendo esto, pero estoy confundido por lo que está escrito en el análisis con un capítulo de argumento radix

tabla de resultados de análisis (_, 3)

¿Por qué es que parseInt(8, 3)NaNy parseInt(16, 3)1?

AFAIK 8 y 16 no son números de base 3, por lo parseInt(16, 3)que NaNtambién deberían volver

los primeros diez números naturales de base 3

Devid Farinelli
fuente
44
Otro problema que se habría resuelto con la escritura estática (o al menos sin convertir implícitamente enteros en cadenas): P
Navin
44
@Navin Esto no tiene nada que ver con la escritura estática versus dinámica (como se nota). El problema aquí es débil en lugar de escribir fuerte.
Sven Marnach
12
Cuando vi el título de esta pregunta pensé para mí mismo, "probablemente sea porque loljavascript". Al ver las respuestas, juzgo que mi instinto fue básicamente correcto.
Ben Millwood

Respuestas:

373

Esto es algo que la gente tropieza todo el tiempo, incluso cuando lo saben. :-) Estás viendo esto por la misma razón que parseInt("1abc")devuelve 1: se parseIntdetiene en el primer carácter no válido y devuelve lo que tenga en ese punto. Si no hay caracteres válidos para analizar, vuelve NaN.

parseInt(8, 3)significa "analizar "8"en base 3" (tenga en cuenta que convierte el número 8en una cadena; detalles en la especificación ). Sin embargo, en base 3, los números de un solo dígito son sólo 0, 1y 2. Es como pedirle que se analice "9"en octal. Como no había caracteres válidos, tienes NaN.

parseInt(16, 3)le pide que analice "16"en la base 3. Como puede analizar el 1, lo hace, y luego se detiene en el 6porque no puede analizarlo. Entonces vuelve 1.


Dado que esta pregunta está recibiendo mucha atención y podría tener un alto puntaje en los resultados de búsqueda, aquí hay un resumen de opciones para convertir cadenas en números en JavaScript, con sus diversas idiosincrasias y aplicaciones (extraídas de otra respuesta mía aquí en SO):

  • parseInt(str[, radix])- Convierte la mayor cantidad posible del comienzo de la cadena en un número entero (entero), ignorando los caracteres adicionales al final. Así parseInt("10x")es 10; El xes ignorado. Admite un argumento opcional de radix (base de números), también lo parseInt("15", 16)es 21( 15en hexadecimal). Si no hay radix, asume decimal a menos que la cadena comience con 0x(o 0X), en cuyo caso se omite y asume hexadecimal. (Algunos navegadores solían tratar cadenas que comienzan con 0octal; ese comportamiento nunca se especificó, y se rechazó específicamente en la especificación ES5). Devuelve NaNsi no se encuentran dígitos analizables.

  • parseFloat(str)- Me gusta parseInt, pero tiene números de coma flotante y solo admite decimales. Una vez más caracteres adicionales en la cadena se tienen en cuenta, por lo que parseFloat("10.5x")es 10.5(el xse ignora). Como solo se admite el decimal, parseFloat("0x15")es 0(porque el análisis termina en x). Devuelve NaNsi no se encuentran dígitos analizables.

  • Unario +, p +str. Ej. - (p. Ej., Conversión implícita) Convierte la cadena completa en un número utilizando coma flotante y la notación de números estándar de JavaScript (solo dígitos y un punto decimal = decimal; 0xprefijo = hexadecimal; 0oprefijo = octal [ES2015 +]; algunas implementaciones lo extienden para tratar una guía 0como octal, pero no en modo estricto). +"10x"es NaNdebido a que el xse no ignorados. +"10"es 10, +"10.5"es 10.5, +"0x15"es 21, +"0o10"es 8[ES2015 +]. Tiene un problema: +""es 0, no NaNcomo se podría esperar.

  • Number(str)- Exactamente como la conversión implícita (por ejemplo, como el unario +anterior), pero más lenta en algunas implementaciones. (No es probable que importe).

TJ Crowder
fuente
8
Entonces, ¿los parseIntprimeros usos toStringen el primer argumento? Eso tendría sentido.
evolutionxbox
16
@evolutionxbox: Sí, es el primer paso del parseIntalgoritmo: ecma-international.org/ecma-262/7.0/…
TJ Crowder
55
Supongo que 123e-2da 1ya que se convierte 1.23primero, y luego el análisis se detiene en el punto decimal
ilkkachu
66
"Esto es algo que las personas tropiezan todo el tiempo, incluso cuando lo saben" -> ¿Soy el único que piensa que esto debería ser un error? Hacer lo mismo en Java, por ejemplo, te dará una NumberFormatExceptioncada vez.
Wim Deblauwe
44
@SvenMarnach: Esa parte de parseInt(coaccionar el primer argumento para encadenar) tiene sentido. El propósito de parseIntes analizar una cadena a un número entero. Entonces, si le das algo que no es una cadena, tiene sentido comenzar con la representación de la cadena. Lo que hace después de que es un todo 'tro historia ...
TJ Crowder
54

Por la misma razón que

>> parseInt('1foobar',3)
<- 1

En el documento , parseInttoma una cadena. Y

Si string no es un string, entonces se convierte en un string

Entonces 16, 8o '1foobar'se convierte primero en cadena.

Luego

Si parseIntencuentra un carácter que no es un número en la raíz especificada, lo ignora y todos los caracteres siguientes

Lo que significa que se convierte hasta donde puede. El 6, 8y foobarse ignoran, y sólo lo que antes se es convertido. Si no hay nada, NaNse devuelve.

njzk2
fuente
0
/***** Radix 3: Allowed numbers are [0,1,2] ********/
parseInt(4, 3); // NaN - We can't represent 4 using radix 3 [allowed - 0,1,2]

parseInt(3, 3); // NaN - We can't represent 3 using radix 3 [allowed - 0,1,2]

parseInt(2, 3); // 2   - yes we can !

parseInt(8, 3); // NaN - We can't represent 8 using radix 3 [allowed - 0,1,2]

parseInt(16, 3); // 1  
//'16' => '1' (6 ignored because it not in [0,1,2])    

/***** Radix 16: Allowed numbers/characters are [0-9,A-F] *****/ 
parseInt('FOX9', 16); // 15  
//'FOX9' => 'F' => 15 (decimal value of 'F')
// all characters from 'O' to end will be ignored once it encounters the out of range'O'
// 'O' it is NOT in [0-9,A-F]

Algunos ejemplos más:

parseInt('45', 13); // 57
// both 4 and 5 are allowed in Radix is 13 [0-9,A-C]

parseInt('1011', 2); // 11 (decimal NOT binary)

parseInt(7,8); // 7
// '7' => 7 in radix 8 [0 - 7]

parseInt(786,8); // 7 
// '78' => '7' => 7 (8 & next any numbers are ignored bcos 8 is NOT in [0-7])

parseInt(76,8); // 62 
// Both 7 & 6 are allowed '76' base 8 decimal conversion is 62 base 10 
SridharKritha
fuente