Skip to content
On this page

14. isNaN 和 Number.isNaN

开局一张图,日常感叹 thanks for inventing js ~ 别急,看完就懂了。

ch-1

isNaN()

我们都知道 NaN 是 JS 中一种特殊的 Number 类型,使用 ===== 都无法进行判断和比较。

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

JS 提供了一种判断 NaN 的方法,就是使用 isNaN 函数。(这里指全局下的 isNaN 方法,浏览器中就是 Window.isNaN

js
isNaN(NaN) // true
isNaN(1 / 'a') // false
1
2

以上都很好理解,1 / 'a' 的计算结果就是 NaN,所以都是 true。但是下面这几个例子可能会让你感到疑惑,明明是判断 NaN 的,传入了非 NaN 值,结果居然返回了 true

js
isNaN('12a') // true
isNaN('aaa') // true
isNaN(undefined) // true
1
2
3

下面这个例子可能会让你更加一头雾水。

js
isNaN([]) // false
isNaN([1]) // false
isNaN([1, 2]) // true
1
2
3

什么?同样是数组,为什么会有不同的表现?再次重申:“计算机没有黑魔法”,在 JS 里面就是,凡是遇到诡异行为就去查看 MDN 文档或者 ES 规范。这里直接给出 ES 规范中的定义:

Link: https://tc39.es/ecma262/#sec-isnan-number

It performs the following steps when called:

  1. Let num be ToNumber(number).
  2. If num is NaN, return true.
  3. Otherwise, return false.

这里直接给出解释了,isNaN 的第一步是触发 ToNumber,这是 JS 底层的一个方法,也就是所谓的隐式强制转换,你可以理解为 Number()

ToNumber: https://tc39.es/ecma262/#sec-tonumber

上面的例子也可以解释了:

js
isNaN('12a') // true,'12a' 试图被转换为数字,但是格式不对,因此是 NaN
isNaN('aaa') // true,同上
isNaN(undefined) // true,同上

isNaN([]) // false,[] => '' => 0 => 0 is not NaN
isNaN([1]) // false,[1] => '1' => 1 => 1 is not NaN
isNaN([1, 2]) // true, [1, 2] => '1,2' => NaN
1
2
3
4
5
6
7

Number.isNaN()

上述规则虽然诡异,但其实也可以理解,毕竟 'aaa' 这种值确实 “不是一个数字”,符合 NaN 的语义 “not a number”。但有时候我们需要更加纯粹的判断 NaN 的更可靠的方法,于是 ES6 中 Number.isNaN 就出现了。

Number.isNaN() 直接判断传入的值是否为 NaN,而不会对其去进行强制转换,是更可靠的方式。

js
Number.isNaN(NaN) // true
Number.isNaN('12a') // false
Number.isNaN('aaa') // false
Number.isNaN(undefined) // false
Number.isNaN([]) // false
Number.isNaN([1]) // false
Number.isNaN([1, 2]) // false
1
2
3
4
5
6
7

还是摘录 ES 规范中的定义:

Link: Number.isNaN(number)

This function performs the following steps when called:

  1. If number is not a Number, return false.
  2. If number is NaN, return true.
  3. Otherwise, return false.

Number.isNaN 首先判断是否为 number 类型,如果不是直接返回 false,然后判断是否为 NaN。所以它的一种 polufill 可以是:

js
Number.isNaN = Number.isNaN || function(value) {
    return typeof value === 'number' && value !== value
}
1
2
3