JavaScript重难点实例精讲
上QQ阅读APP看书,第一时间看更新

1.2.3 isNaN()函数与Number.isNaN()函数对比

Number类型数据中存在一个比较特殊的数值NaN(Not a Number),它表示应该返回数值却并未返回数值的情况。

NaN存在的目的是在某些异常情况下保证程序的正常执行。例如0/0,在其他语言中,程序会直接抛出异常,而在JavaScript中会返回“NaN”,程序可以正常执行。

NaN有两个很明显的特点,第一个是任何涉及NaN的操作都会返回“NaN”,第二个是NaN与任何值都不相等,即使是与NaN本身相比。


NaN == NaN;  // false

在判断NaN时,ES5提供了isNaN()函数,ECMAScript 6(后续简称ES6)为Number类型增加了静态函数isNaN()。

既然在ES5中提供了isNaN()函数,为什么要在ES6中专门增加Number.isNaN()函数呢?两者在使用上有什么区别呢?

1. isNaN()函数

首先我们来看看isNaN()函数的作用,它用来确定一个变量是不是NaN。NaN是一个Number类型的数值,只不过这个值无法用真实的数字表示。

如果传递的参数是Number类型数据,可以很容易判断是不是NaN。如果传递的参数是非Number类型,它返回的结果往往会让人费解。

例如下面判断一个空对象{}的代码。


isNaN({});  // true

空对象{}明明不是一个NaN的数据,应该返回的是“false”,为什么会返回“true”呢?

这里我们首先要知道NaN产生的条件,一方面是在数据运算时,返回了一个无法表示的数值,例如0 / 0就会返回“NaN”。有一点需要注意的是除了0 / 0,其他数据除以0都返回“Infinity”。

另一方面是在需要做强制类型转换时,某些数据不能直接转换为数值类型,就会返回“NaN”,例如1 - 'a' = NaN,因为字符串'a'无法参与数值运算。

而isNaN()函数正好会进行数据的类型转换,它在处理的时候会去判断传入的变量值能否转换为数字,如果能转换成数字则会返回“false”,如果无法转换则会返回“true”。

接下来就通过下面这些代码来测试一下。


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

isNaN(true);      // false,Number(true)会转换成数字1
isNaN(null);      // false,Number(null)会转换成数字0
isNaN(1);         // false
isNaN('');        // false,Number('')会转换为成数字0
isNaN("1");            // false,字符串"1"可以转换成数字1
isNaN("JavaScript");   // true,字符串"JavaScript"无法转换成数字
// Date类型
isNaN(new Date());     // false
isNaN(new Date().toString());  // true

Date是一种比较特殊的类型,当我们调用new Date()函数生成的实例并转换为数值类型时,会转换为对应的时间戳,例如下面的代码。


Number(new Date()); // 1543333199705

因此isNaN(new Date())会返回“false”。

而当我们调用了toString()函数时,返回的是一串字符串表示的时间,无法转换成数值类型,因此isNaN(new Date().toString())会返回“true”。

2. Number.isNaN()函数

既然在全局环境中有isNaN()函数,为什么在ES6中会专门针对Number类型增加一个isNaN()函数呢?

这是因为isNaN()函数本身存在误导性,而ES6中的Number.isNaN()函数会在真正意义上去判断变量是否为NaN,不会做数据类型转换。只有在传入的值为NaN时,才会返回“true”,传入其他任何类型的值时会返回“false”。

我们可以通过以下这些代码做测试。


Number.isNaN(NaN);        // true
Number.isNaN(undefined);   // false
Number.isNaN(null);       // false
Number.isNaN(true);       // false
Number.isNaN('');         // false
Number.isNaN(123);        // false

上面代码运行后,除了传入NaN会返回“true”以外,传入其他的值都会返回“false”。如果在非ES6环境中想用ES6中的isNaN()函数,该怎么办呢?我们有以下兼容性处理方案。


// 兼容性处理
if(!Number.isNaN) {
    Number.isNaN = function (n) {
       return n !== n;
    }
}

因为在所有类型的数据中,如果一个变量和自身作比较,只有在变量值为NaN时才会返回“false”,其他情况都是返回“true”。

所以n !== n返回“true”,只有在n为NaN的时候才成立。

3. 总结

isNaN()函数与Number.isNaN()函数的差别如下。

· isNaN()函数在判断是否为NaN时,需要先进行数据类型转换,只有在无法转换为数字时才会返回“true”;

· Number.isNaN()函数在判断是否为NaN时,只需要判断传入的值是否为NaN,并不会进行数据类型转换。