Validação de números decimais em JavaScript: por que IsNumeric() quebra o código e como corrigir
\n\nTodo desenvolvedor que escreveu em JavaScript por pelo menos uma semana, mais cedo ou mais tarde, enfrentou a tarefa: "Verificar se uma string é um número". Parece simples, não? A função embutida isNaN() ou parseFloat() — e pronto. Mas não é bem assim. A pergunta "Validate decimal numbers in JavaScript — IsNumeric()" no Stack Overflow acumulou centenas de milhares de visualizações e dezenas de respostas contraditórias. Por quê? Porque JavaScript é uma linguagem onde typeof NaN === 'number', e uma string vazia é considerada zero.
Neste artigo, não vamos apenas fornecer a função isNumeric() pronta. Vamos analisar os 5 erros mais comuns e perigosos que até programadores experientes cometem, e mostrar como evitá-los. Você aprenderá por que isNaN é uma armadilha, como funciona a coerção de tipos e qual método de validação de números em JS realmente usar em produção.
Por que isNaN() é o mal (e quando funciona)
\n\nVamos começar pelo óbvio. Muitos iniciantes escrevem assim:
\n\nfunction isNumeric(n) {\n return !isNaN(n);\n}\n\n\nÀ primeira vista, é lógico: se não é NaN, então é número. Mas vamos testar:
\n\nconsole.log(isNumeric('123')); // true — ok\nconsole.log(isNumeric('12.3')); // true — ok\nconsole.log(isNumeric('')); // true — UPA! String vazia é número?\nconsole.log(isNumeric(' ')); // true — espaço também é número?\nconsole.log(isNumeric(null)); // true — null é número?\nconsole.log(isNumeric(true)); // true — true é 1\n\n\nErro nº1: isNaN() primeiro converte o argumento em número, depois verifica. A string vazia '' é convertida em 0, null em 0, true em 1. Como resultado, a função considera números o que não são números.
Existe uma variante estrita — Number.isNaN() (ES6), mas ela verifica apenas se o valor é exatamente NaN, sem conversão. Para validação de números, também não serve.
parseFloat: herói ou vilão?
\n\nA segunda abordagem popular é usar parseFloat():
function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n}\n\n\nEsta versão já é melhor, mas tem outro problema:
\n\nconsole.log(isNumeric('123abc')); // true — parseFloat pega '123', e 'abc' ignora\nconsole.log(isNumeric('12.3.4')); // true — o segundo ponto o parseFloat simplesmente não percebe\nconsole.log(isNumeric('Infinity')); // true — infinito é número?\n\n\nErro nº2: parseFloat() analisa a string até o primeiro caractere inválido. A string '123abc' para ele é 123. Mas o usuário pode ter pressionado uma tecla extra acidentalmente, e somos obrigados a detectar isso.
Erro nº3: isFinite() elimina Infinity e -Infinity, mas permite NaN e undefined. O problema é que isFinite(null) retorna true, porque null é convertido em 0.
Erro nº4: Expressões regulares — panaceia ou novo inferno?
\n\nQuando os desenvolvedores percebem que as funções embutidas não são confiáveis, muitas vezes vão para o outro extremo — expressões regulares. E aí começa o verdadeiro caos.
\n\nAqui está uma regex típica, mas perigosa:
\n\nfunction isNumeric(n) {\n return /^\\d+$/.test(n);\n}\n\n\nProblemas:
\n- \n
- Não permite pontos decimais (
'12.3'— false) \n - Não permite números negativos (
'-5'— false) \n - Não permite notação científica (
'1e5'— false) \n
Aqui está um "u