Por que é que parseInt (8,3) == NaN e parseInt (16,3) == 1?


191

Estou lendo isso, mas estou confuso com o que está escrito na análise com um capítulo de argumento de raiz

tabela de resultados da análise (_, 3)

Por que parseInt(8, 3)NaNe parseInt(16, 3)1?

AFAIK 8 e 16 não são de base 3-números, de modo que parseInt(16, 3)deve retornar NaNdemasiado

os primeiros dez números naturais da base 3


4
No entanto, outra questão que teria sido resolvido pela tipagem estática (ou pelo menos não converter implicitamente inteiros para cordas): P
Navin

4
@ Navin Isso não tem nada a ver com digitação estática versus digitação dinâmica (como você observa). O problema aqui é fraco, em oposição à digitação forte.
Sven Marnach

12
Quando vi o título desta pergunta, pensei: "provavelmente porque loljavascript". Vendo as respostas, julgo que meu instinto está basicamente correto.
precisa

Respostas:


373

Isso é algo que as pessoas tropeçam o tempo todo, mesmo quando sabem disso. :-) Você está vendo isso pela mesma razão que parseInt("1abc")retorna 1: parseIntpara no primeiro caractere inválido e retorna o que tiver nesse momento. Se não houver caracteres válidos para analisar, ele retornará NaN.

parseInt(8, 3)significa "analisar "8"na base 3" (observe que ele converte o número 8em uma string; detalhes nas especificações ). Mas, na base 3, os números de um dígito são apenas 0, 1e 2. É como pedir para analisar "9"em octal. Como não havia caracteres válidos, você conseguiu NaN.

parseInt(16, 3)está pedindo que ele analise "16"na base 3. Como ele pode analisar o 1, ele faz e, então, para no 6porque não pode analisá-lo. Então ele retorna 1.


Como essa pergunta está recebendo muita atenção e pode ter uma classificação alta nos resultados de pesquisa, aqui estão algumas opções para converter seqüências de caracteres em números em JavaScript, com suas várias idiossincrasias e aplicativos (extraídos de outra resposta minha aqui no SO):

  • parseInt(str[, radix])- Converte o máximo possível do início da string em um número inteiro (inteiro), ignorando caracteres extras no final. Assim parseInt("10x")é 10; o xé ignorado. Suporta um argumento opcional de base (número base), assim parseInt("15", 16)como 21( 15em hexadecimal). Se não houver raiz, assume decimal, a menos que a cadeia comece com 0x(ou 0X); nesse caso, ignora-as e assume hexadecimal. (Alguns navegadores costumavam tratar cadeias iniciando com 0octal; esse comportamento nunca foi especificado e foi especificamente proibido na especificação ES5.) Retorna NaNse nenhum dígito analisável for encontrado.

  • parseFloat(str)- Como parseInt, mas possui números de ponto flutuante e suporta apenas decimal. Novamente, caracteres extras na string são ignorados, o mesmo parseFloat("10.5x")ocorre 10.5(o xé ignorado). Como apenas decimal é suportado, parseFloat("0x15")é 0(porque a análise termina no x). Retorna NaNse nenhum dígito analisável for encontrado.

  • Unário +, por exemplo +str- (por exemplo, conversão implícita) Converte toda a string em um número usando ponto flutuante e a notação de número padrão do JavaScript (apenas dígitos e um ponto decimal = decimal; 0xprefixo = hex; 0oprefixo = octal [ES2015 +]; algumas implementações a estendem tratar um líder 0como octal, mas não no modo estrito). +"10x"é NaNporque o nãox é ignorado. é , é , é , é [ES2015 +]. Tem uma pegadinha: é , não como você poderia esperar.+"10"10+"10.5"10.5+"0x15"21+"0o10"8+""0NaN

  • Number(str)- Exatamente como a conversão implícita (por exemplo, a unária +acima), mas mais lenta em algumas implementações. (Não é provável que isso importe.)


8
Então, os parseIntprimeiros usos toStringno primeiro argumento? Isso faria sentido.
Evoluçãoxbox

16
@evolutionxbox: Sim, é o primeiro passo do parseIntalgoritmo: ecma-international.org/ecma-262/7.0/…
TJ Crowder

5
Suponho que 123e-21uma vez que se transforma em 1.23primeiro e, em seguida, a análise para no ponto decimal?
Ilkkachu

6
"Isso é algo que as pessoas tropeçam o tempo todo, mesmo quando sabem disso" -> eu sou o único que acha que isso deve ser um bug? Fazer o mesmo em Java, por exemplo, fornecerá a NumberFormatExceptioncada vez.
Wim Deblauwe

4
@SvenMarnach: Essa parte de parseInt(coagir o primeiro argumento a string) faz sentido. O objetivo de parseInté analisar uma string para um número inteiro. Portanto, se você der algo que não é uma string, é bom fazer com que a representação da string comece. O que ele faz depois disso é uma história totalmente diferente ...
TJ Crowder /

54

Pela mesma razão que

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

No documento , parseIntpega uma string. E

Se a string não for uma string, ela será convertida em uma string

Assim 16, 8ou '1foobar'é primeiro convertido para string.

Então

Se parseIntencontrar um caractere que não seja um numeral no radical especificado, ele o ignorará e todos os caracteres seguintes.

Ou seja, ele converte até onde pode. A 6, 8e foobarsão ignorados, e só o que está antes de ser convertido. Se não houver nada, NaNserá retornado.


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]

Mais alguns exemplos:

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 
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.