Javascript 中 isNaN 与 Number.isNaN 的混淆

我对 NaN 的工作原理感到困惑。我已经执行了 isNaN(undefined)它返回了 true。但是如果我使用 Number.isNaN(undefined),它返回的是 false。所以我该用哪个。也解释了为什么结果会如此不一致。

28101 次浏览

To quote from a ponyfoo article on numbers in ES6:

Number.isNaN is almost identical to ES5 global isNaN method. Number.isNaN returns whether the provided value equals NaN. This is a very different question from “is this not a number?”.

So isNaN just checks whether the passed value is not a number or cannot be converted into a Number. Number.isNaN on the other hand only checks if the value is equal to NaN (it uses a different algorithm than === though).

The String 'ponyfoo' for example is not a number and cannot be converted into a number, but it is not NaN.

Example:

Number.isNaN({});
// <- false, {} is not NaN
Number.isNaN('ponyfoo')
// <- false, 'ponyfoo' is not NaN
Number.isNaN(NaN)
// <- true, NaN is NaN
Number.isNaN('pony'/'foo')
// <- true, 'pony'/'foo' is NaN, NaN is NaN


isNaN({});
// <- true, {} is not a number
isNaN('ponyfoo')
// <- true, 'ponyfoo' is not a number
isNaN(NaN)
// <- true, NaN is not a number
isNaN('pony'/'foo')
// <- true, 'pony'/'foo' is NaN, NaN is not a number
  • isNaN converts the argument to a Number and returns true if the resulting value is NaN.
  • Number.isNaN does not convert the argument; it returns true when the argument is a Number and is NaN.

So which one i should use.

I am guessing you are trying to check if the value is something that looks like a number. In which case the answer is neither. These functions check if the value is an IEEE-754 Not A Number. Period. For example this is clearly wrong:

var your_age = "";
// user forgot to put in their age
if (isNaN(your_age)) {
alert("Age is invalid. Please enter a valid number.");
} else {
alert("Your age is " + your_age + ".");
}
// alerts "Your age is ."
// same result when you use Number.isNaN above

Also why there is so discrepancy in the result.

As explained above Number.isNaN will return false immediately if the argument is not a Number while isNaN first converts the value to a Number. This changes the result. Some examples:

                |       Number.isNaN()       |        isNaN()
----------------+----------------------------+-----------------------
value           | value is a Number | result | Number(value) | result
----------------+-------------------+--------+---------------+-------
undefined       | false             | false  | NaN           | true
{}              | false             | false  | NaN           | true
"blabla"        | false             | false  | NaN           | true
new Date("!")   | false             | false  | NaN           | true
new Number(0/0) | false             | false  | NaN           | true

In shortly,

isNaN()

will check if the convert of value to Number (type) are failed

For example'abc'


Number.isNaN()

will check if the given value type is Number but not valid number

For example: 'bb'/33

I found that if you want to check if something is numbery (or not), then a combination of Number.isNaN() with either Number.parseInt() or Number.parseFloat() (depending on what you expect) to cover most use cases:

consider: test a bunch of different input vars against several is number tests:

r = [NaN, undefined, null, false, true, {}, [], '', ' ', 0, 1, '0', '1']
.map(function(v){return [
v,
isNaN(v),
Number.isNaN(v),
Number.isInteger(v),
Number.parseInt(v, 10),
Number.isNaN( Number.parseInt(v, 10))
];});
console.table(r);
// or if console.table() not available:
r.join('\n', function(v){v.join(',')} );

result:

NaN      , true , true , false, NaN, true
undefined, true , false, false, NaN, true
null     , false, false, false, NaN, true
false    , false, false, false, NaN, true
true     , false, false, false, NaN, true
Object   , true , false, false, NaN, true
Array(0) , false, false, false, NaN, true
''       , false, false, false, NaN, true
' '      , false, false, false, NaN, true
0        , false, false, true , 0  , false
1        , false, false, true , 1  , false
'0'      , false, false, false, 0  , false
'1'      , false, false, false, 1  , false

Note the last column, which is usually what I want in my experience.

Number.isNaN()

This method returns true if the value is of the type Number, and equates to NaN. Otherwise it returns false. e.g.

Number.isNaN(123) //false


Type of 123 is number but 123 is not equal to NaN, therefore it returns false.




Number.isNaN('123') //false
    

Type of 123 is string & '123' is not equal to NaN, therefore it returns false.




Number.isNaN(NaN) //true


Type of NaN is number & NaN is equal to NaN, therefore it returns true.




Number.isNaN('NaN') //false


Type of 'NaN' is string & 'NaN' is not equal to NaN, therefore it returns false.

global isNaN() function

The global isNaN() function converts the tested value to a Number, then tests it.

isNaN(123) //false
isNaN('123') //false
isNaN(NaN) //true
isNaN('NaN') //true

First, forget about the useless meaning of the value NaN, just treat it as bad number. As soon as you saw NaN, read it as 'bad number'.

Number.isNaN is a more safe and robust version of isNaN, isNaN has a bug,

isNaN(NaN) // true, this is the supposed result, the argument is NaN
isNaN('hello') // true, but this is misleading, cuz `hello` is not NaN

isNaN can't distinguish NaN with other not-number values, such as characters.

So a new method comes into play.

Number.isNaN checks if the value is number firstly, if it is not a number, it returns false immediately.

Number.isNaN('hello') // false, 'hello' is not NaN, this is the supposed result