Validación de números decimales en JavaScript: por qué IsNumeric() rompe el código y cómo solucionarlo
\n\nTodo desarrollador que haya escrito en JavaScript al menos una semana, tarde o temprano se ha enfrentado a la tarea: «Verificar si una cadena es un número». Parecería que no podría ser más sencillo. La función incorporada isNaN() o parseFloat() — y listo. Pero no es tan simple. La pregunta «Validate decimal numbers in JavaScript — IsNumeric()» en Stack Overflow ha acumulado cientos de miles de visitas y decenas de respuestas contradictorias. ¿Por qué? Porque JavaScript es un lenguaje donde typeof NaN === 'number', y una cadena vacía se considera cero.
En este artículo no solo daremos una función isNumeric() lista para usar. Analizaremos los 5 errores más comunes y peligrosos que cometen incluso programadores experimentados, y mostraremos cómo evitarlos. Aprenderás por qué isNaN es una trampa, cómo funciona la conversión de tipos y qué método de validación de números en JS se usa realmente en producción.
Por qué isNaN() es malo (y cuándo funciona)
\n\nEmpecemos con lo obvio. Muchos principiantes escriben así:
\n\nfunction isNumeric(n) {\n return !isNaN(n);\n}\n\n\nA primera vista es lógico: si no es NaN, entonces es un número. Pero probemos:
\n\nconsole.log(isNumeric('123')); // true — ok\nconsole.log(isNumeric('12.3')); // true — ok\nconsole.log(isNumeric('')); // true — ¡UPS! ¿Una cadena vacía es un número?\nconsole.log(isNumeric(' ')); // true — ¿un espacio también es un número?\nconsole.log(isNumeric(null)); // true — ¿null es un número?\nconsole.log(isNumeric(true)); // true — true es 1\n\n\nError nº1: isNaN() primero convierte el argumento a número y luego verifica. La cadena vacía '' se convierte en 0, null en 0, true en 1. Como resultado, la función considera números lo que no lo son.
Existe una variante estricta — Number.isNaN() (ES6), pero solo verifica si el valor es exactamente NaN, sin conversión. Para validar números tampoco sirve.
parseFloat: ¿héroe o villano?
\n\nEl segundo enfoque popular es usar parseFloat():
function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n}\n\n\nEsta variante es mejor, pero tiene otro problema:
\n\nconsole.log(isNumeric('123abc')); // true — parseFloat toma '123' e ignora 'abc'\nconsole.log(isNumeric('12.3.4')); // true — parseFloat simplemente no nota el segundo punto\nconsole.log(isNumeric('Infinity')); // true — ¿el infinito es un número?\n\n\nError nº2: parseFloat() analiza la cadena hasta el primer carácter no válido. La cadena '123abc' para él es 123. Pero el usuario pudo haber presionado una tecla extra accidentalmente, y debemos detectarlo.
Error nº3: isFinite() descarta Infinity y -Infinity, pero deja pasar NaN y undefined. El problema es que isFinite(null) devuelve true, porque null se convierte en 0.
Error nº4: Expresiones regulares — ¿panacea o nuevo infierno?
\n\nCuando los desarrolladores se dan cuenta de que las funciones incorporadas no son fiables, a menudo caen en el otro extremo: las expresiones regulares. Y ahí comienza el verdadero caos.
\n\nAquí hay una expresión regular típica pero peligrosa:
\n\nfunction isNumeric(n) {\n return /^\\d+$/.test(n);\n}\n\n\nProblemas:
\n- \n
- No acepta puntos decimales (
'12.3'— false) \n - No acepta números negativos (
'-5'— false) \n - No acepta notación científica (
'1e5'— false) \n
Aquí hay una expresión regular «m