JavaScript—NaN 特殊的数值(Number 类型)

5 阅读3分钟

NaN 是 Not a Number 的缩写,它是 JavaScript 中一个特殊的数值(Number 类型),用于表示 “不是一个合法的数字”。

一、核心特性

  1. 类型是 Numbertypeof NaN 的结果是 'number',这是一个非常重要且容易被忽略的特性。

    console.log(typeof NaN); // 'number'
    
  2. 唯一不与自身相等的值NaN 是 JavaScript 中唯一一个不等于自身的值。这是它最奇特的性质。

    console.log(NaN === NaN); // false
    
  3. 传播性任何与 NaN 进行的数学运算,结果几乎都是 NaN

    console.log(NaN + 5);        // NaN
    console.log(NaN * 10);       // NaN
    console.log(Math.sqrt(NaN)); // NaN
    

二、产生 NaN 的常见场景

NaN 通常在以下几种情况下出现:

  1. 无效的数学运算

    • 一个非数字字符串尝试被转换为数字失败时。
    • 数字除以零(0 / 0),注意:非零数字 / 0 的结果是 Infinity 或 -Infinity,而不是 NaN
    • 负数的平方根。
    const a = Number('hello'); // NaN
    const b = '123' - 'abc';   // NaN
    const c = 0 / 0;           // NaN
    const d = Math.sqrt(-1);   // NaN
    
  2. 函数返回

    • 许多数学函数在接收到无效参数时,会返回 NaN
    const e = Math.acos(2);    // NaN (acos的参数范围是 -1 到 1)
    const f = parseInt('abc'); // NaN
    

三、如何判断一个值是否为 NaN

由于 NaN === NaN 为 false,我们不能使用相等运算符来判断一个值是否为 NaN。正确的方法有两种:

  1. 使用全局函数 isNaN()

    • isNaN() 函数会尝试将传入的参数转换为数字。如果转换失败,它就返回 true,否则返回 false
    • 注意:这是一个有缺陷的函数,因为它的转换逻辑可能导致一些非 NaN 的值也返回 true
    console.log(isNaN(NaN));       // true
    console.log(isNaN('hello'));   // true (因为 'hello' 无法被转换为数字)
    console.log(isNaN('123'));     // false (可以被转换为数字 123)
    console.log(isNaN(undefined)); // true (一个历史遗留问题)
    
  2. 使用 ES6 新增的 Number.isNaN()

    • Number.isNaN() 是判断 NaN 的正确方法。它不会进行类型转换,只有当传入的值严格等于 NaN 时才返回 true
    console.log(Number.isNaN(NaN));       // true
    console.log(Number.isNaN('hello'));   // false (因为 'hello' 是字符串,不是 NaN)
    console.log(Number.isNaN(123));       // false
    console.log(Number.isNaN(undefined)); // false
    
  3. 利用 NaN 不等于自身的特性

    • 一个巧妙的技巧是检查一个值是否不等于它自己。
    function isActuallyNaN(value) {
      return value !== value;
    }
    console.log(isActuallyNaN(NaN)); // true
    console.log(isActuallyNaN(123)); // false
    

    这个方法和 Number.isNaN() 的效果完全相同。

四、总结与实践建议

  • 理解 NaN 的本质:它是一个表示 “计算失败” 或 “无效数字” 的特殊数值。
  • 避免使用 isNaN() :由于其怪异的类型转换行为,很容易引发 bug。
  • 推荐使用 Number.isNaN() :这是判断一个值是否为 NaN 的标准、可靠方法。
  • 在计算前进行类型检查:为了从根源上避免 NaN,在进行数学运算前,最好先确保操作数是有效的数字。
function safeAdd(a, b) {
  if (Number.isNaN(Number(a)) || Number.isNaN(Number(b))) {
    throw new Error('传入的参数必须是有效的数字');
  }
  return Number(a) + Number(b);
}

console.log(safeAdd(5, '10')); // 15
console.log(safeAdd(5, 'hello')); // Error: 传入的参数必须是有效的数字