JavaScript中的IsNumeric:数字验证的5个致命错误

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

JavaScript中的十进制数字验证:为什么IsNumeric()会破坏代码以及如何修复

\n\n

每个至少写过一周JavaScript的开发者,迟早都会遇到这样一个任务:“检查一个字符串是否为数字”。看起来,这能有多难?内置函数 isNaN() 或 parseFloat() 就能轻松搞定。但事实并非如此。Stack Overflow上的问题 “Validate decimal numbers in JavaScript — IsNumeric()” 获得了数十万次浏览和几十个相互矛盾的答案。为什么?因为JavaScript是一种 typeof NaN === 'number' 且空字符串被视为零的语言。

\n\n

在本文中,我们不仅会给出一个现成的 isNumeric() 函数。我们还将分析 5个最常见且危险的错误,即使是经验丰富的程序员也常会犯,并展示如何避免它们。您将了解到为什么 isNaN 是一个陷阱,类型转换是如何工作的,以及哪种JS数字验证方法真正适用于生产环境。

\n\n

为什么isNaN()是邪恶的(以及它何时有效)

\n\n

让我们从显而易见的地方开始。许多新手会这样写:

\n\n
function isNumeric(n) {\n  return !isNaN(n);\n}\n
\n\n

乍一看很合理:如果不是NaN,那就是数字。但让我们测试一下:

\n\n
console.log(isNumeric('123'));    // true — 正常\nconsole.log(isNumeric('12.3'));   // true — 正常\nconsole.log(isNumeric(''));       // true — 哎呀!空字符串是数字?\nconsole.log(isNumeric(' '));      // true — 空格也是数字?\nconsole.log(isNumeric(null));     // true — null是数字?\nconsole.log(isNumeric(true));     // true — true是1\n
\n\n

错误 #1: isNaN() 首先将参数转换为数字,然后进行检查。空字符串 '' 被转换为 0,null 被转换为 0,true 被转换为 1。结果,该函数将不是数字的东西当成了数字。

\n\n

有一个严格版本——Number.isNaN() (ES6),但它只检查值是否为NaN,而不进行类型转换。它也不适用于数字验证。

\n\n

parseFloat:英雄还是恶棍?

\n\n

第二种流行的方法是使用 parseFloat():

\n\n
function isNumeric(n) {\n  return !isNaN(parseFloat(n)) && isFinite(n);\n}\n
\n\n

这个版本好一些,但它有另一个问题:

\n\n
console.log(isNumeric('123abc')); // true — parseFloat会截取'123',忽略'abc'\nconsole.log(isNumeric('12.3.4')); // true — parseFloat根本不会注意到第二个点\nconsole.log(isNumeric('Infinity')); // true — 无穷大是数字?\n
\n\n

错误 #2: parseFloat() 解析字符串直到第一个无效字符。字符串 '123abc' 对它来说是 123。但用户可能不小心按了多余的键,我们必须捕获这种情况。

\n\n

错误 #3: isFinite() 排除了 Infinity 和 -Infinity,但放过了 NaN 和 undefined。问题在于 isFinite(null) 返回 true,因为 null 被转换为 0。

\n\n

错误 #4:正则表达式——万能药还是新的地狱?

\n\n

当开发者意识到内置函数不可靠时,他们常常会走向另一个极端——正则表达式。这时真正的混乱就开始了。

\n\n

这是一个典型但 危险 的正则表达式:

\n\n
function isNumeric(n) {\n  return /^\\d+$/.test(n);\n}\n
\n\n

问题:

\n
    \n
  • 不允许小数点('12.3' — false)
  • \n
  • 不允许负数('-5' — false)
  • \n
  • 不允许科学计数法('1e5' — false)
  • \n
\n\n

这是一个“完

博客

书籍推荐