NaN , а не число, это особый
значение, используемое для обозначения непредставительного значения. С JavaScript,
тип
NaN
может возникнуть некоторая путаница, начиная со своего typeof
и всего до способа обработки сравнения.
Несколько операций могут привести к NaN
как результат. Вот несколько примеров (следите за JSBin: jsbin.com/yulef ):
Math.sqrt(-2) Math.log(-1) 0/0 parseFloat('foo')
Первой ловушкой для многих начинающих JavaScript обычно является неожиданный результат вызова typeof
:
console.log(typeof NaN); // 'number'
В некотором смысле, хотя NaN не должен быть числом, его тип — число. Понял?
Сохраняйте спокойствие, так как это будет продолжать приводить ко многим путаницам. Давайте сравним два NaN:
var x = Math.sqrt(-2); var y = Math.log(-1); console.log(x == y); // false
Может быть, это потому, что вместо этого мы должны использовать оператор строгого равенства (===)? Очевидно нет.
var x = Math.sqrt(-2); var y = Math.log(-1); console.log(x === y); // false
Arrgh! Может быть потому, что они являются NaN от двух разных операций? Что о…
var x = Math.sqrt(-2); var y = Math.sqrt(-2); console.log(x == y); // false
Еще безумнее
var x = Math.sqrt(-2); console.log(x == x); // false
Как насчет сравнения двух реальных NaN?
console.log(NaN === NaN); // false
Поскольку существует множество способов представления NaN, имеет смысл, что один NaN не будет равен другому NaN. Тем не менее, вот почему я иногда чирикаю:
Это ваше ежегодное напоминание о том, что NaN означает «не NaN».
Чтобы решить эту проблему, первоначально я намеревался представить это предложение для ECMAScript 7:
Но, конечно, решения (и обходные пути) уже существуют сегодня.
Давайте познакомимся с глобальной функцией isNaN :
console.log(isNaN(NaN)); // true
Увы, isNan()
есть свои известные недостатки:
console.log(isNaN('hello')); // true console.log(isNaN(['x'])); // true console.log(isNaN({})); // true
Это часто приводит к ряду различных обходных путей. Одним из примеров является использование неотражающей природы NaN (см., Например, записку Кит Кембридж ):
var My = { isNaN: function (x) { return x !== x; } }
Another example is to check for the value’s type first (to prevent coercion):
My.isNaN = function(x) { return typeof x === 'number' && isNaN(x); };
Note: The coercion that is being blocked here is related to isNaN
. As an exercise, compare the result of isNaN(2)
, isNaN('2')
and isNaN('two')
.
Fortunately, for the upcoming ECMAScript 6, there is Number.isNaN()
which provides a true NaN
detection (BTW, you can already use this function in the latest version of Chrome and Firefox). In the latest draft from April 2014 (Rev 24), this is specified in Section 20.1.2.4:
When the Number.isNaN is called with one argument number, the following steps are taken:
1. If Type(number) is not Number, return false.
2. If number is NaN, return true.
3. Otherwise, return false.
In other words, it returns true
only if the argument is really NaN:
console.log(Number.isNaN(NaN)); // true console.log(Number.isNaN(Math.sqrt(-2))); // true console.log(Number.isNaN('hello')); // false console.log(Number.isNaN(['x'])); // false console.log(Number.isNaN({})); // false
Next time you need to deal with NaN, be extremely careful!