深入理解 JavaScript 中的 NaN

424 阅读3分钟

深入理解 JavaScript 中的 NaN

在 JavaScript 的世界里,NaN是一个颇为特殊的存在,初看它,你可能会觉得有些矛盾,明明叫 “不是一个数字(not a number)”,可typeof NaN的结果却为number。今天,咱们就来深入探究一番这个特殊的NaN。

一、NaN 的产生

NaN的诞生有多种情境:

  1. 一个不能被解析的数字

当我们试图将明显不是数字格式的内容强制转换为数字时,就会得到NaN。例如:

Number('abc'); // NaN
Number(undefined); // NaN

这里,字符串'abc'和特殊值undefined都无法被正确解析成合法数字,所以结果为NaN。

  1. 失败的操作

在数学运算领域,一些不合理的操作也会催生NaN。像对负数求对数(在实数范围内)、对负数求平方根(同样在实数范围内)以及求超出反余弦函数定义域的值的反余弦,都会得到这个特殊结果:

Math.log(-1); // NaN
Math.sqrt(-1); // NaN
Math.acos(2);  // NaN
  1. 一个运算符为 NaN

一旦参与运算的某个值是NaN,那整个运算结果大概率也是NaN。因为NaN就像一个 “黑洞”,只要碰到它,正常的数字运算规则就被打破。比如:

NaN + 1;     // NaN
10 / NaN;    // NaN

二、注意点

NaN有个极为独特的性质,它是 JavaScript 中唯一一个和自身不相等的值:

NaN === NaN;  // false

这一点与我们常规对相等性的认知截然不同,却也是理解NaN行为的关键。

三、如何辨别 NaN

在实际编程中,常常需要判断一个值是不是NaN。JavaScript 提供了全局函数isNaN(),但它的行为有些微妙。

起初看,它似乎是用来判断一个值是不是NaN:

isNaN(NaN);    // true
isNaN(10);      // false

可实际上,isNaN()并非单纯判断是不是NaN这个值。它首先会尝试把传入的值转换成数字,若转换结果是NaN,函数就会返回true。这就导致对非数字的判断容易出错,例如:

isNaN('abc');     // true

所以,当我们真想确定一个值是不是NaN时,可以采用以下两种靠谱方法:

  1. 方法一:将 isNaN () 和 typeof 结合来判断
function isValueNaN(value) {
    return typeof value === 'number' && isNaN(value);
}

这种方式先通过typeof确认值是数字类型,再结合isNaN进一步判断,避免了非数字值的误判。

  1. 方法二:值是否与本身不相等(NaN 是唯一有这样特征的值)
function isValueNaN(value) {
    return value!== value;
}

巧妙利用了NaN与自身不相等的特性来精准识别。

  1. 方法三:Number.isNaN()
  • Number.isNaN() :它只判断传入的值是否严格等于NaN,不会进行类型转换。也就是说,只有当参数是真正的NaN值时,才会返回true

  • 全局isNaN() :在判断之前会先尝试将传入的参数转换为数字类型,然后再判断是否为NaN。这可能会导致一些意外的结果,例如:

isNaN('abc'); // true,因为'abc'被转换为NaN
Number.isNaN('abc'); // false

应用场景

总之,理解NaN的特性、产生方式以及如何准确辨别它,对编写健壮的 JavaScript 代码至关重要,希望这篇分享能帮大家更好地驾驭这个特殊的 “数字”。