# isNaN与Number.isNaN的区别

很长一段时间,我都不知道NaNnot a number的意思,惭愧。

NaN是个特殊的存在,x === x这个真理被它颠覆了。也可以理解,不是数字嘛,不是数字的东西太多了。

我们经常有这样的需求,想把一个字符串转成数字,但又担心转换失败,于是代码会这么写:

function isNumber(str) {
  return !isNaN(Number(str))
}

最近才发现,这么写并不是最优的。直接用!isNaN(str)就可以了。为什么呢?

原来,isNaN函数会首先尝试将这个参数转换为数值,然后才会对转换后的结果是否是NaN进行判断。

那为什么又出现了Number.isNaN呢?

我们先看下面的例子:

isNaN(NaN);       // true
isNaN(undefined); // true
isNaN({});        // true

isNaN(true);      // false
isNaN(null);      // false
isNaN(37);        // false

// strings
isNaN("37");      // false: 可以被转换成数值37
isNaN("37.37");   // false: 可以被转换成数值37.37
isNaN("37,5");    // true
isNaN('123ABC');  // true:  parseInt("123ABC")的结果是 123, 但是Number("123ABC")结果是 NaN
isNaN("");        // false: 空字符串被转换成0
isNaN(" ");       // false: 包含空格的字符串被转换成0

// dates
isNaN(new Date());                // false
isNaN(new Date().toString());     // true

isNaN("blabla")   // true: "blabla"不能转换成数值
                  // 转换成数值失败, 返回NaN

isNaN会先进行数值转换,它导致我们前面说的not a number这个语义化不对了,空字符串、日期怎么也是false?它们不是数字难道是错的?

所以,Number.isNaN就来了,它不会进行类型转换,意思是我只判断是不是NaN,类型不是数字的直接给false——对不起,你不在我的判定范围。

最明显的区别是:

isNaN('abc'); // true
Number.isNaN('abc'); // false

isNaN(undefined); // true
Number.isNaN(undefined); // false

isNaN({});        // true
Number.isNaN({});        // false