¿Cómo evito el comportamiento octal parseInt de JavaScript?

282

Intente ejecutar lo siguiente en JavaScript:

parseInt('01'); //equals 1
parseInt('02'); //equals 2
parseInt('03'); //equals 3
parseInt('04'); //equals 4
parseInt('05'); //equals 5
parseInt('06'); //equals 6
parseInt('07'); //equals 7
parseInt('08'); //equals 0 !!
parseInt('09'); //equals 0 !!

Acabo de enterarme por completo que JavaScript cree que el cero inicial indica un número entero octal , y dado que no existe "8"o "9"en base-8, la función devuelve cero. Nos guste o no, esto es por diseño .

¿Cuáles son las soluciones alternativas?

Nota: En aras de la exhaustividad, estoy a punto de publicar una solución, pero es una solución que odio, así que publique otras / mejores respuestas.


Actualizar:

La quinta edición del estándar JavaScript ( ECMA-262 ) introduce un cambio radical que elimina este comportamiento. Mozilla tiene una buena reseña .

Portman
fuente
21
Paso 1) Hazte un favor e incluye siempre la raíz como se menciona en las respuestas anteriores, así como en el libro de Doug. Paso 2) Si te tomas en serio el aprendizaje de JavaScript, obtén una copia del libro de Doug. Es invaluable Mi libro favorito hasta ahora. Aquí hay una revisión para su información: realtech.burningbird.net/learning-javascript/basics/…
fuentesjr
8
En los navegadores compatibles con ECMAScript 5th Edition, como Internet Explorer 9, el parámetro base predeterminado es 10(decimal) a menos que el número a analizar tenga como prefijo 0x, por ejemplo 0xFF, en cuyo caso el parámetro base predeterminado es 16. Esperemos que algún día este problema Será un recuerdo lejano.
Andy E
2
¿Qué tal solo +'08' === 8? ¡Cierto! Tal vez realmente necesites parseInttu código real, pero no para lo anterior.
kojiro
1
a) esto no es un error, corrige el título b)Number('08')
OnTheFly
44
@portman: "la quinta edición ... introduce un cambio radical que elimina este comportamiento" Probablemente valga la pena señalar que incluso en la tercera edición (hace 13 años), las implementaciones fueron "alentadas" a no hacerlo: "Cuando Radix es 0o undefinedy el número de la cadena empieza con un 0dígito no seguida de una xo X, a continuación, la aplicación puede, a su discreción, interpretar el número, ya sea como octal o como decimal. se anima a las implementaciones de interpretar los números en este caso como decimal. " ( mi énfasis)
TJ Crowder

Respuestas:

328

Este es un problema común de Javascript con una solución simple:

Simplemente especifique la base , o 'radix', así:

parseInt('08',10); // 8

También puedes usar Número :

Number('08'); // 8
Paolo Bergantino
fuente
57
Número . Glorioso.
Portman
10
Number necesita comillas alrededor del 08. También se advierte que Number ('08 .123 ') producirá 8.123 como salida. Si realmente desea un número entero, no use Number (o coincida con el patrón de su entrada para garantizar solo números enteros).
Jason S
3
Número (08); me da 8 en Firefox e IE.
Paolo Bergantino
3
no es parte del estándar ECMAscript. Estoy probando en JSDB que usa Spidermonkey 1.7 (= motor Firefox JS), y se queja "08 no es una constante octal legal ECMA-262"
Jason S
55
Aún así, use '08' entre comillas. 08 no cumple con el estándar ECMA-262 y no se garantiza que tenga éxito sin advertencias y / o errores y / o un comportamiento específico en particular.
Jason S
43

Si sabe que su valor estará en el rango entero de 32 bits con signo, entonces ~~xhará lo correcto en todos los escenarios.

~~"08" === 8
~~"foobar" === 0
~~(1.99) === 1
~~(-1.99)  === -1

Si busca binary not ( ~), la especificación requiere una conversión "ToInt32" para el argumento que realiza la conversión obvia a Int32 y se especifica para obligar a los NaNvalores a cero.

Sí, esto es increíblemente hack pero es muy conveniente ...

Karl Guertin
fuente
2
¿Por qué dos operaciones cuando una binaria o sería suficiente?
Oleg V. Volkov
@Oleg, ¿por qué sería suficiente?
Sebastian
3
@SebastianGodelet, | 0.
Oleg V. Volkov
@Grodriguez, y cuando 0 en | 0 es una cadena?
Oleg V. Volkov
Toda esta pregunta trata sobre alternativas a parseInt para convertir cadenas en enteros. Por lo tanto: siempre.
Grodriguez
24

De la documentación de parseInt , use el argumento de la raíz opcional para especificar base-10:

parseInt('08', 10); //equals 8
parseInt('09', 10); //equals 9

Esto me parece pedante, confuso y detallado (¿realmente, un argumento adicional en cada análisis?), Así que espero que haya una mejor manera.

Portman
fuente
66
si no le gusta la verbosidad, simplemente haga su propia función que llame a la función incorporada y complete los argumentos que siempre mantiene constantes.
Jason S
3
Riiiiiiight, porque no es como si todas las personas en StackOverflow lo reprendieran por escribir la función parseIntB10. Escribir su propia función de contenedor es una idea terrible para este propósito.
Stefan Kendall
2
@iftrue: Creo que te perdiste mi punto. Personalmente, no me importa simplemente hacer parseInt (someString, 10) en todas partes para asegurarme de forzar la base 10. Al OP parece que no le gusta este enfoque, por lo que sugerí una alternativa, que no usaría personalmente, pero tal vez cumpla con su necesidades. (este es aparentemente el pensamiento detrás de JQuery: hacerlo conveniente agregando complejidad adicional. No uso JQuery, pero a muchas personas les resulta útil)
Jason S
44
En realidad, es realmente importante ajustar parseIntpara un uso conveniente en expresiones funcionales, como mapen ["7","4","09","5"].map(parseInt); Mappasará el índice del elemento en la matriz como el segundo argumento, que será interpretado parseIntcomo la base a menos que lo ajuste.
Plynx
11
function parseDecimal(s) { return parseInt(s, 10); }

editar: hacer su propia función, hacer lo que realmente quiere, es solo una opción si no le gusta agregar ", 10" todo el tiempo a la llamada parseInt (). Tiene la desventaja de ser una función no estándar: más conveniente para usted si la usa mucho, pero quizás más confusa para otros.

Jason S
fuente
10

Especifique la base:

var number = parseInt(s, 10);
RichieHindle
fuente
Wow, ustedes son rápidos. Incluso tuve mi respuesta en el portapapeles. ¿Estás conectado directamente a Internet, al estilo neo?
Portman
1
¿Por qué demonios no está predeterminado en la base 10?
Tom Gullen
2
Tal vez porque no se entiende principalmente como una función de conversión de Cadena-> Número, sino una función que lee un Número de una Cadena de número base b.
artistoex
2
está predeterminado en la base 10, pero los ceros iniciales son una forma generalizada de indicar octal.
Nathan
7

¿Sería muy malo reemplazar parseInt con una versión que asume decimal si no tiene un segundo parámetro? (nota - no probado)

parseIntImpl = parseInt
parseInt = function(str, base){return parseIntImpl(str, base ? base : 10)}
Andrew Duffy
fuente
2
sí, eso sería malo: rompería otro código que se basara en el comportamiento estándar.
jes5199
44
Eso es cierto, pero no hay mucho de eso. Tampoco es un comportamiento estándar: el soporte octal es opcional.
Andrew Duffy el
2
Pero también está dejando caer el soporte hexadecimal que no es opcional, ¿verdad? Esto siempre debe ser cierto: parseInt("0xFFFFFF") === 16777215pero con tu truco travieso ya no funcionaparseInt("0xFFFFFF") === 0
Timo
6

También puede, en lugar de usar parseFloat o parseInt, usar el operador unario ( + ).

+"01"
// => 1

+"02"
// => 2

+"03"
// => 3

+"04"
// => 4

+"05"
// => 5

+"06"
// => 6

+"07"
// => 7

+"08"
// => 8

+"09"
// => 9

y por si acaso

+"09.09"
// => 9.09

MDN Link

El operador unario más precede a su operando y lo evalúa, pero intenta convertirlo en un número, si aún no lo está. Aunque la negación unaria (-) también puede convertir no números, unario plus es la forma más rápida y preferida de convertir algo en un número , ya que no realiza ninguna otra operación en el número.

SoEzPz
fuente
5

¿Qué tal esto para decimal:

('09'-0) === 9  // true

('009'-0) === 9 // true
Gordon K
fuente
4

Si ya ha realizado una gran cantidad de codificación con parseInt y no desea agregar ", 10" a todo, puede anular la función para que la base 10 sea la predeterminada:

window._oldParseInt = window.parseInt;
window.parseInt = function(str, rad) {
    if (! rad) {
        return _oldParseInt(str, 10);
    }
    return _oldParseInt(str, rad);
};

Eso puede confundir a un lector posterior, por lo que hacer una función parseInt10 () podría explicarse más por sí mismo. Personalmente, prefiero usar una función simple que tener que agregar ", 10" todo el tiempo, solo crea más oportunidades para errores.

ingrediente_15939
fuente
0

Este problema no se puede replicar en las últimas Chrome ni Firefox (2019).

Andrija
fuente