isNaN、Number.isNaN、lodash.isNaN 的区别
isNaN、Number.isNaN、lodash.isNaN 的区别
- 一、isNaN() 的作用
- 二、什么是 NaN?
- 三、isNaN() 的必要性
- 四、isNaN() 比较
- 1. 全局的isNaN()
- 2. Number.isNaN()
- 3. lodash.isNaN()
- 五、总结
- 六、附加
一、isNaN() 的作用
检查是否为 NaN
的值,是返回 true
, 否则返回 false
。
二、什么是 NaN?
首先,我们应该先理解一下 NaN
是什么? 当算术运算返回一个未定义的或无法表示的值时,就用 NaN
表示, 例如: 0 / 0 = NaN (注:其它数除以0不会得到 NaN,例如 1 / 0 = Infinity)
; 或者将某些 不能强制转换为数值 的 非数值 转换为 数值 的时候,也会得到 NaN
。例如:Number('y') = NaN
。
三、isNaN() 的必要性
在 javascript 中,值的比较方式可以通过 相等操作符(== 或 ===)来直接进行比较,但 NaN
不可以。在 javascript 中规定,NaN 自身永不等于自身。因此, NaN === NaN
和 NaN == NaN
返回的结果都是 false
。那么,isNaN
就很有必要性了。
四、isNaN() 比较
目前常见的 isNaN()
函数, 包括全局的 isNaN()
、 ECMAScript (ES2015) 提供的 Number.isNaN()
和 比较常用的插件 lodash 封装的 lodash.isNaN()
。通过比较三种 isNaN()
的实现方式,对比他们各自的实现原理。
1. 全局的isNaN()
全局的 isNaN(value)
方法,在判断之前,会先通过类型转换 Number(value)
将 入参 value 强制转换为 number
类型,然后再判断其是否是 NaN
值。
// polyfill
var isNaN = function (value) {var n = Number(value);return n !== n;
};
// test
isNaN(null) // false:Number(null) = 0
isNaN(true) // false: Number(true) = 1
isNaN(1) // false:Number(1) = 1
isNaN('1') // false: Number('1') = 1
isNaN(1+1) // false: Number(1+1) = 2
isNaN(1/0) // false: Number(1/0) = Infinity
isNaN('') // false:Number('') = 0
isNaN(new Date()) // false: Number(new Date()) = 1679627563755, 是一个时间戳,属于 Number 类型isNaN(NaN) // true: Number(NaN) = NaN
isNaN(undefined) // true: Number(undefined) = NaN
isNaN({}) // true:Number({}) = NaN
isNaN('37,9') // true: Number('37,9') = NaN
isNaN('1+1') // true: Number('1+1') = NaN
isNaN(0/0) // true: Number(0/0) = NaN
isNaN('ceshi') // true: Number('ceshi') = NaN
isNaN(new Date().toString()) // true: Number(new Date().toString()) = NaN
2. Number.isNaN()
Number.isNaN(value)
方法,在判断之前,会先判断入参 value
是否是 number
类型(不会进行隐式转换),再判断是否是 NaN
。即只有在入参 value
为 number
类型,且值是 NaN
的情况下,才会返回 true
,其余返回 false
。
// polyfill
Number.isNaN = function (value) {return typeof value === 'number' && isNaN(value)
}
// test
Number.isNaN(null) // false: typeof(null) = 'object'
Number.isNaN(true) // false: typeof(true) = 'boolean'
Number.isNaN(undefined) // false: typeof(undefined) = 'undefined'
Number.isNaN('ceshi') // false: typeof('ceshi') = 'string'
Number.isNaN({}) // false: typeof({}) = 'object'
Number.isNaN(new Date()) // false: typeof(new Date()) = 'object'
Number.isNaN(1) // false: typeof(1) = 'number', isNaN(1) = false
Number.isNaN('1') // false: typeof('1') = 'string'
Number.isNaN(1+1) // false: 1 + 1 = 2, typeof(2) = 'number', isNaN(2) = false
Number.isNaN('1+1') // false: typeof('1+1') = 'string'
Number.isNaN(1/0) // false: 1 / 0 = Infinity, typeof(Infinity) = 'number', isNaN(Infinity) = falseNumber.isNaN(NaN) // true: typeof(NaN) = 'number', isNaN(NaN) = true
Number.isNaN(0/0) // true: 0 / 0 = NaN, typeof(NaN) = 'number', isNaN(NaN) = true
3. lodash.isNaN()
lodash.isNaN(value)
方法的判断方式和 Number.isNaN()
相似,,都是先通过类型转换将 value
转变成 number
类型,再结合 NaN 自身永不等于自身
去判断 value
值是否是 NaN。
lodash.isNaN() = function (value) {// typeof value === 'number' && value != +value;return isNumber(value) && value != +value;
}
// test
lodash.isNaN(null) // false: isNumber(null) = false
lodash.isNaN(true) // false: isNumber(true) = false
lodash.isNaN(undefined) // false: isNumber(undefined) = false
lodash.isNaN({}) // false: isNumber({}) = false
lodash.isNaN(new Date()) // false: isNumber(new Date()) = falselodash.isNaN(1) // false: isNumber(1) = true, 1 = +1
lodash.isNaN('1') // false: isNumber('1') = false
lodash.isNaN(1/0) // false: 1/0 = Infinity, isNumber(Infinity) = true, +Infinity = Infinitylodash.isNaN(NaN) // true: isNumber(NaN) = true && NaN != +NaN
lodash.isNaN(0/0) // true: 0 / 0 = NaN, isNumber(NaN) = true && NaN != +NaN
五、总结
全局的 isNaN()
缺点是, 方法中的 Number()
方法会将一些 非数值类型的值
,例如, {}
、undefined
、'37,9'
等值, 通过转换之后得到 NaN
。但事实上,我们常用的情况下,是希望能排除因 Number()
方法带来的一些类型转化所带来的 NaN
异常问题,在这一点上,Number.isNaN()
和 lodash.isNaN()
更符合我们的预期。
六、附加
针对上述 isNaN()
三种方法,我们提出一个思考,假设,现在有一个需求,要判断 value
值是否是 纯数字,比如1,2,-100...
,满足返回 true
,否则返回 false
:
由于 NaN
也是属于 number
类型,如果只用 isNumber()
判断,则 NaN
会返回 true,与我们想要的结果不一致;如果只用 !isNaN()
判断,那么,像字符串 1
、true
等情况会返回 true
,与我们想要的结果也不一致。故一般是结合使用 isNumber(value) && !isNaN(value)
。