Статьи

Загадочный случай JavaScript NaN

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».

23 октября 2013 г.

Чтобы решить эту проблему, первоначально я намеревался представить это предложение для 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!