0%

JavaScript中最狠的角色:NaN

JavaScript中最狠的角色:NaN,为什么说它是最狠的角色呢?因为它狠起来,连自己都不放过!

如果要在纯数学中找到一个变量x,且满足 x != x,那么很遗憾,数学中不存在这样的变量。但是在JS的世界中却存在这样一个变量,它就是 NaN,它自己和自己不相等,够不够狠?

1
2
NaN == NaN // false
NaN === NaN // false

NaN的全称是“Not a Number”,它表示一个非数字的值。通常情况下,NaN出现在以下几种情况:

什么情况会产生NaN?

以下情况都会产生NaN

失败的数字类型转换

如果尝试将一个非数字类型的变量转换为数字类型,但转换失败,则会产生NaN

1
2
Number(undefined); // NaN
parseInt('abc'); // NaN

无效的数学运算

在数学运算中,如果运算无法产生一个数字,则会产生NaN。例如:

1
2
3
Math.sqrt(-1); // NaN,负数的平方根是虚数,不是数字 
Math.log(-1); // NaN,负数的对数是未定义的
Math.pow('abc', 2); // NaN,'abc'不能转换为数字

无穷值

当一个数学运算的结果是无穷大或无穷小时,JS会将其转换为NaN。例如:

1
2
3
1 / 0; // Infinity
0 * Infinity; // NaN,0乘以无穷大是未定义的
Infinity - Infinity; // NaN,无穷大减去无穷大是未定义的

非数字类型的运算

在JS中,如果对非数字类型的值进行数学运算,通常会产生NaN。例如:

1
2
3
'abc' * 2; // NaN,字符串不能参与数学运算
undefined + 1; // NaN,undefined转换为数字时是NaN
2 ** NaN; // NaN不能参加数学运算

其他情况

这个情况和第一种类似,就是将一个非数字类型表示为数字类型时,如果转换失败,也会产生NaN。例如:

1
2
new Date("blabla").getTime(); // NaN,无法将无效的日期字符串转换为时间戳
"".charCodeAt(1); // NaN,空字符串的第二个字符不存在

唯一的例外

在JS所支持的所有数学运算中,只有一个运算不会产生NaN,那就是0次幂运算。

1
NaN ** 0 // 1

如何判断NaN?

给定一个变量x,如何判断它是否是NaN呢?由开头的介绍可知,我们无法使用==或者===来判断NaN,所以JS提供了专门用于判断NaN的函数:

  • isNaN(x):这个函数主要用来判断x是否能转换为数字,如果不能转换为数字,则返回true,否则返回false。注意,这个函数会对非数字类型的值进行隐式转换。
  • Number.isNaN(x):这个函数是ES6引入的,它只会判断x是否是NaN,不会进行隐式转换。如果xNaN,则返回true,否则返回false
  • Object.is(x, NaN):这个函数也是ES6引入的,它可以用来判断x是否是NaN

看几个列子,理解一下。

1
2
3
4
5
6
7
8
9
isNaN(NaN); // true
isNaN('abc'); // true,因为'abc'不能转换为数字
isNaN(`123`); // false,因为123可以转换为数字

Number.isNaN(NaN); // true
Number.isNaN('abc'); // false,因为'abc'不是NaN

Object.is(NaN, NaN); // true
Object.is(NaN, 123); // false

面试题

如果让你写一个函数判断一个变量是否是NaN,你会怎么写?我们可以根据NaN的特性:NaN与自身不相等来实现这个函数。

1
2
3
4
5
6
function isReallyNaN(x) {
return x !== x; // NaN是唯一一个不等于自己的值
}

console.log(isReallyNaN(NaN)); // true
console.log(isReallyNaN(123)); // false