持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
1、NaN特点
对于NaN有以下特点:
- typeof是数字(
typeof NaN结果为'number'
) - 不等于自己(NaN == NaN : false、NaN === NaN:false)
- 不能被更改(在控制台输入Object.getOwnPropertyDescriptor(window, 'NaN')可以发现configurable是false)
2、isNaN
本质是调用一个toNumber方法,尝试对数据进行转换,如果是NaN就返回true,否则返回false
其语义化代码如下:
const isNaN = function(val) {
return Object.is(Number(val), NaN);
}
对于不同数据类型在进行toNumber转换时会返回不同结果:
数据类型 | 结果 |
---|---|
undefined | NaN |
null | 0 |
boolean | true转换为1、false转换为0 |
number | 不发生转换,返回其本身 |
string | 1.如果字符串中只包含数值字符 ,包括数值字符前的加、减号 则转换为一个十进制数值 (会忽略前面的0) 2.如果字符串包含有效的浮点值 ,则转换为相应的浮点值(忽略前面的0)3.如果字符串为有效的十六进制格式 如:"0xf"则会转为与该十六进制值对应的十进制值 4.如果是空字符串 ,则转为0 5.如果字符串包含 除了以上情况外的其他字符 则返回NaN |
object | 调用valueOf()方法并按照字符串转数字规则转换。如果转换结果为NaN,则调用toString()方法,再按照转换字符的规则转换。 |
symbol | 抛出异常 |
bigint | 抛出异常 |
由于symbol与bigint在进行toNumber转换时会抛出异常所以isNaN方法并不是安全的
3、Number.isNaN
此方法会先判断这个数据是否为数字(typeof是否为number),如果为数字了再判断该值是不是等于NaN
其语义化代码如下:
Number.isNaN = function(val) {
if(typeof val !== 'number') {
return false
}
return Object.is(val, NaN);
}
4、严格判断NaN的各种方式
Number.isNaN
可以直接通过ES6新增的Number.isNaN判断,如果是NaN会返回true,不是NaN会返回false
console.log(Number.isNaN(NaN)) // true
console.log(Number.isNaN(2)) // false
自身比较
利用NaN不等于其本身的特点可以进行判断
function isNaNVal(val) {
return val !== val;
}
console.log(isNaNVal(NaN)); // true
Object.is
Object.is在对比两个值是否相等时接近“===”,但又有以下不同:
- 使用===判断时 0 与 +0 、-0均相等,而NaN与NaN不相等
- 使用Object.is判断时0 与 +0相等、0与-0不相等、-0与-0相等;而且NaN等于其本身
function isNaNVal(val) {
return Object.is(val, NaN);
}
console.log(isNaNVal(NaN));
typeof + isNaN
如果Number上不存在isNaN方法时,可以采用typeof + isNaN的方式来进行判断
function isNaNVal(val) {
return typeof val === 'number' && isNaN(val)
}
如果Number上有isNaN方法,那么直接采用即可,考虑兼容性的话可以写成如下方式:
if (!("isNaN" in Number)) {
Number.isNaN = function(val) {
return typeof val === 'number' && isNaN(val)
}
}
5、关于NaN的陷阱
先来看如下代码:
const arr = [NaN];
console.log(arr.indexOf(NaN)); // -1
console.log(arr.includes(NaN)); // true
可以看出ES5中的indexOf方法不能够识别NaN,而ES6中的includes方法可以准确识别NaN
这是由于这两种方法底层实现原理不同:
- indexOf是调用的内部的Number::equal
Number::equal(x, y)
如果x为NaN则返回false、如果y为NaN也返回false,所以是找不到NaN的
- includes是调用的内部的Number::sameValueZero
Number::sameValueZero(x, y)
如果x为NaN、y为NaN则返回true,所以此方法是能够严格判断出NaN的