一、特性
ES6之后,Number也多了一个静态属性NaN
1. typeof
typeof NaN // number
typeof Number.NaN // number
2. 不等于自身
NaN === NaN // false
Number.NaN === NaN // false
3. 不能修改自身属性
新的ES标准中, 不可配置,不可枚举。也就是说不可以被删除delete,不可以被改写, 也不可以改写配置。
delete NaN // false
NaN = 1 // 1
NaN == 1 // false
delete Number.NaN // false
Number.NaN = 1 // 1
Number.NaN == 1 // false
Reflect.getOwnPropertyDescriptor(window, 'NaN')
// {value: NaN, writable: false, enumerable: false, configurable: false}
二、isNaN 和 Number.isNaN
1. isNaN
isNaN() 是一个全局方法。
其本质是检查 toNumber 返回值, 如果是NaN,就返回 true,反之返回 false 。
toNumber 方法, 大致的逻辑如下:
Argument Type | Result |
---|---|
Undefined | Return NaN. |
Null | Return +0𝔽. |
Boolean | If argument is true, return 1𝔽. If argument is false, return +0𝔽. |
Number | Return argument (no conversion). |
String | Return ! StringToNumber(argument). |
Symbol | Throw a TypeError exception. |
BigInt | Throw a TypeError exception |
简单来说就是,
Number.isNaN = function (val){
return Object.is(Number(val), NaN);
}
2. Number.isNaN
判断一个值是否是数字,并且值等于NaN
ES标准的描述:
- If Type(number) is not Number, return false.
- If number is NaN, return true.
- Otherwise, return false.
可以语义化为
Number.isNaN = function(val){
if(typeof val !== "number"){
return false
}
return Object.is(val, NaN);
}
3. isNaN和Number.isNaN的区别
- Number.isNaN是严格判断, 必须严格等于NaN。是不是NaN这个值
- isNaN是通过内部的 toNumber 转换结果来判定的。Number转换的返回值是不是NaN
- Number.isNaN是ES6的语法,固然存在一定的兼容性问题。
三、严格判断NaN
1. Number.isNaN (ES6)
Number.isNaN(NaN) // true
Number.isNaN(1) // false
2. Object.is (ES6)
Object.is(NaN, NaN); // true
Object.is(1, NaN); // false
Object.is("123", NaN) // false
3. 自身比较 (ES5)
function isNaNVal(val){
return val !== val;
}
isNaNVal(NaN) // true
isNaNVal(1) // false
4. typeof + NaN (ES5)
这是MDN推荐的垫片,有些兼容低版本的库就是这么实现的, 也是ES标准的精准表达
function isNaNVal(val){
return typeof val === 'number' && isNaN(val)
}
四、indexOf 和 includes 识别NaN
var arr=[NaN];
arr.indexOf(NaN) // -1
arr.includes(NaN) // true
1. includes
ES标准的Array.prototype.includes 比较值相等调用的是内部的 SameValueZero ( x, y )方法,其会检查值第一值是不是数字,如果是数字,调用的是 Number::sameValueZero(x, y), 其具体比较步骤:
- If x is NaN and y is NaN, return true.
- If x is +0𝔽 and y is -0𝔽, return true.
- If x is -0𝔽 and y is +0𝔽, return true.
- If x is the same Number value as y, return true.
- Return false.
其先对NaN进行了比较,所以能检查NaN, 这里还有一个额外信息,比较的时候+0和-0是相等的, 要区分+0和-0还得用Object.is
2. indexOf
ES标准中 Array.prototype.indexOf 值比较调用的是IsStrictlyEqual(searchElement, elementK), 其如果检查到第一个值为数字,调用的 Number::equal(x, y), 其具体比较步骤:
- If x is NaN, return false.
- If y is NaN, return false.
- If x is the same Number value as y, return true.
- If x is +0𝔽 and y is -0𝔽, return true.
- If x is -0𝔽 and y is +0𝔽, return true.
- Return false.
可以看到,任何一个为NaN,就直接返回false,必然不能严格的检查NaN.