昨天帮朋友看一个表单校验,输入框填了 12abc 却通过了检查,代码里写的是 if (!isNaN(value))。我一看就知道问题出在哪儿,isNaN 会把空字符串当成 0 处理,还会做类型转换,判断结果经常反直觉。

isNaN 到底怎么坑人

全局的 isNaN 会先把参数转成 Number 再判断。isNaN('') 返回 false,isNaN(' ') 也是 false,isNaN(null) 照样 false。也就是说一个空输入会被当成合法数字,表单就放过去了。它的设计初衷是判断计算结果是不是 NaN,不是判断值本身是不是数字。

优先用 Number.isFinite

ES6 之后多了几个不那么绕的方法:

Number.isFinite(123)   // true
Number.isFinite('123') // false
Number.isNaN(NaN)      // true
Number.isInteger(5.0)  // true

Number.isFinite 不会做类型转换,传字符串直接返回 false,这在表单场景里正合适。要判断是不是整数就用 Number.isInteger,要判断 NaN 就用 Number.isNaN。

整数、小数、科学计数法的取舍

  • 只允许整数:先 Number.isInteger(Number(v)),再补一步非空判断
  • 允许小数:用 Number.isFinite,再配合正则 ^-?\d+(\.\d+)?$ 限制格式
  • 允许科学计数法:正则要加上 [eE][+-]?\d+ 这一段
  • 货币金额:干脆别用浮点,转成整数分来算

别忘了 typeof

如果变量可能是任意类型,先看 typeof v === 'number',再判断 Number.isFinite(v),两步合起来最稳。数据来自接口时尤其要这样,接口返回 null 或者字符串的情况太常见了。

一句话:新代码统一用 Number.isFinite,老代码里见着裸 isNaN 就顺手换掉,踩坑概率能降一大半。