[前端日记]1.x.1/解读NaN

Javascript中有一个特殊的对象:NaN,它是「not a number」的缩写。总结了以下几点需要注意,如有错误,烦请指正:P

1. Javascript中返回NaN的情况


就目前所学来看,以下两种情况会返回NaN:

  • 表达式计算
    一个表达式中如果有减号 (-)、乘号 (*) 或 除号 (/) 等运算符时,JS 引擎在计算之前,会试图将表达式的每个分项转化为Number 类型(使用 Number()做转换)。如果转换失败,表达式将返回 NaN 。
    一句话理解:任何数除以、减、乘非数值(undefined、string、object)时,都会直接返回NaN
100 - '2a' ; // NaN 
'100' / '20a'; // NaN 
'20a' * 5 ; // NaN
undefined / 5; // NaN
undefined * "hello" // NaN
  • 类型转换失败
    使用 parseIntparseFloatNumber 将一个非数字的值转化为数字时,表达式返回 NaN
"abc" - 3   // NaN
parseInt("abc")  // NaN
parseFloat("abc") //NaN
Number("abc")    //NaN

NaN带来的坑


陷阱1:typeof NaN // 返回number

这种情况下返回了number。
在JS中,整数和浮点数都统称为Number,除此之外,还有一个特殊的数值类型就是NaN。他不是一个数字,而是一种数值类型,这也解释了typeof NaN // 返回number

陷阱2:NaN == NaN // 返回false

无论相等还是全等,NaN与自身比较都返回false
因为NaN表示一个无法表示的值,而有很多方法来表示一个非数字,所以一个非数字不会等于另一个为NaN的非数字。比如0/0返回NaN,0/'fail'也返回NaN,而0/0 != 0/’fail’,所以NaN == NaN返回false。

陷阱3:判断一个值是否为NaN

如上,==,===均不能用来判断一个值是否是NaN。必须使用Number.isNaN()isNaN函数来检验,下面我们来看下他们的用法。

isNaN()


通常我们用isNaN来判断一个值是否是NaN,如下

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

isNaN(true) // false,为1
isNaN(null) // false,为0
isNaN("") // false ,为0
isNaN(" ") // false,带空格的字符串转换为数字为0
isNaN([]) // false,空数组转换为数字为0

isNaN()接收一个参数,参数可以为任意数据类型。如果接收的参数是数字类型,返回false;如果是其他类型(除了数字的任何其他类型),则返回true;

  1. 若接收的参数为数字类型,返回false,表示不是NaN
  2. 若参数为非数字类型,会通过toNumber()将值强制转换为数值,再进行判断。
  3. 如接受的参数是空,比如[](空数组)、“”(空字符串)、null等,会在过程中转换为数字类型的0,从而返回false。

如下代码,在调用isNaN()时,遇到字符串会强制进行隐式转换。

isNaN("1");            // false "1" 被转化为数字 1,因此返回false
isNaN("Hello World"); // true "Hello World" 被隐式转化成数字`NaN`

总结一下isNaN()的坑:
如果传入的参数不是number类型,isNaN()会尝试将参数转换为数值,然后再对转换后的数值进行判断。因此,就算对于能够被转换为数值的数据类型来说(要特别注意,空字符串、布尔、null、空数组会返回0,布尔值会返回对应数值),返回false值也是反直觉的。

说到底,其实是Javascript强制类型转换的坑啊!

ES6新特性 Number.isNaN()


例如,空字符串就明显不是数值,但是还是返回了0,这是相当的反直觉的!

所以,我们能否不进行隐式转换来判断NaN呢?答案是,可以的!

ES6引入了另一种判断方法来填坑——Number.isNaN(x)。通过这个函数来检测x是否是一个非数值,这方法比isNaN()更为可靠。只有在参数是真正的数值类型,且判断后值为 NaN 的时候才会返回 true。

Number.isNaN(NaN)  // true,NaN既是数值类型,返回的又是NaN
Number.isNaN("NaN") // false,这里"NaN"是string,不是数字类型,所以直接返回false

Number.isNaN("hello") // false
isNaN("hello") // true,Number("hello")返回NaN,再判断isNaN(NaN) // true

Number.isNaN({}) // false
isNaN({}) // true,Number({})返回NaN,判断同上

Number.isNaN("") // false
isNaN("") // true

总的来说,Number.isNaN()进行了更严格的判断。

你可能感兴趣的:([前端日记]1.x.1/解读NaN)