NaN? Back
Before talking about something about NaN
, we should know that what it means. Actually NaN
is also called as Not-A-Number value, which means that the value is not a number. It's usually returned as a result after failed to calculate some expression like Math.sqrt(-1)
, or parseInt('number')
. Of course, you may also have seen Number.NaN
, which is completely same as NaN
. Furthermore, they're both Number types:
console.log(Object.prototype.toString.call(NaN)); /** => "[object number]" */
console.log(Object.prototype.toString.call(Number.NaN)); /** => "[object number]" */
Although NaN
is a Number, it is not equal to itself:
console.log(NaN == NaN); /** => false */
console.log(NaN === NaN); /** => false */
However, the global method isNaN
will always return true when judging whether a value is NaN
:
isNaN(NaN); /** => true */
isNaN(undefined); /** => true */
isNaN({}); /** => true */
isNaN('number'); /** => true */
That's because the value passed into the method will be firstly converted into Number types:
Number(NaN); /** => NaN */
Number(undefined); /** => NaN */
Number({}); /** => NaN */
Number("abc"); /** => NaN */
Then, ES6 has imported Number.isNaN()
to judge strictly:
isNaN = function (value) {
return Number(value) === NaN;
};
Number.isNaN = Number.isNaN || function (value) {
return typeof value === 'number' && isNaN(value);
};
However, this implementation still have a problem:
Number.isNaN(new Number(NaN)); /** => false */
Therefore, underscore has fixed by implementing this:
_.isNaN = function (obj) {
return Object.prototype.toString.call(obj) === '[object Number]' && obj !== +obj;
};
But this causes a huge problem:
_.isNaN(new Number(0)); /** => true */
_.isNaN(new Number(1)); /** => true */
Therefore, the most elegant way to implement this method should be:
_.isNaN = function (obj) {
return Object.prototype.toString.call(obj) === '[object Number]' && isNaN(obj);
};