某天写需求做数字格式化,需要判断接口返回的字段是否是数字,如果不是则显示--,第一反应是使用isNaN()判断,结果我大意了……
isNaN()
以下的参数都不是数字,然而使用isNaN判断却发现了大宝贝,只有少数几种类型符合期望,到底是哪里出了问题呢?
isNaN(null)
// output: false
isNaN(undefined)
// output: true
isNaN('')
// output: false
isNaN('1')
// output: false
isNaN('a')
// output: true
isNaN(true)
// output: false
isNaN([])
// output: false
isNaN([1])
// output: false
isNaN([1, 2])
// output: true
isNaN({})
// output: true
isNaN({a: 123})
// output: true
复制代码
首先查看MDN上的定义:
The
isNaN()
function determines whether a value isNaN
or not. Because coercion inside theisNaN
function can be surprising, you may alternatively want to useNumber.isNaN()
.
文档表明了isNaN
是存在一些不可预知的情况,再去查看tc39关于isNaN的描述,发现处理流程是这样的:
- 根据下面表格的规则,将参数转换成Number
参数类型 | 转换结果 |
---|---|
Undefined | NaN |
Null | 0 |
Boolean | true返回1, false返回0 |
Number | 不转换 |
String | 转换为数字,如果报错,则返回NaN |
Symbol | 报错 |
BigInt | 报错 |
Object | 首先判断这个参数的对象类型的preferredType转换为对应的原始数据类型,然后再根据上面对应的类型进行转换 |
ps1: []
、[1]
、[1, 2]
这三种情况的结果不一样,是因为它们先根据Object类型转化为字符串''
、'1'
、'1, 2'
,然后再根据String类型的规则转换为数字0
、1
、NaN
,因此最后的结果是false
、false
、true
ps2: preferredType为Number的常见对象包括Date
等
- 如果得到的转换结果是NaN,则返回true,否则返回false
Number.isNaN()
按照MDN的提示,想起还有一个Number.isNaN()
的方法可以一试,在tc39关于Number.isNaN中,简而言之是判断是否是数字类型且是NaN
,是则返回true
,否则返回false
。
结论
综上所述,不考虑Symbol
和BigInt
的情况下,基本上isNaN(val)
等价于Number.isNaN(Number(val))
回到一开始的场景,我的解决方案如下:
typeof val === 'number' && !Number.isNaN(val) ? val : '--'
复制代码