NaN

Глобальна властивість NaN – значення, що представляє "Not-A-Number" – нечисло.

Спробуйте його в дії

Значення

Те саме числове значення, що й Number.NaN.

Атрибути властивості NaN
Записна ні
Перелічувана ні
Конфігуровна ні

Опис

NaN – властивість глобального об'єкта. Інакше кажучи, це змінна в глобальній області видимості.

В сучасних браузерах NaN є неналаштовною властивістю, недоступною для запису. Навіть коли це не так, слід уникати її змін.

Є п'ять різновидів операцій, що повертають NaN:

  • Провал перетворення на число (тобто явного перетворення, як то parseInt("blabla"), Number(undefined), або ж неявного, як то Math.abs(undefined))
  • Математичні операції, чий результат не є дійсним числом (наприклад, Math.sqrt(-1))
  • Невизначені форми (наприклад, 0 * Infinity, 1 ** Infinity, Infinity / Infinity, Infinity - Infinity)
  • Метод чи вираз, чий операнд є або зводиться до NaN (наприклад, 7 ** NaN, 7 * "blabla") — а отже, NaN є заразним значенням
  • Інші випадки, коли недійсне значення представляється як число (наприклад, недійсне значення Date new Date("blabla").getTime(), "".charCodeAt(1))

NaN і його логіка не були винайдені JavaScript. Його семантика полягає в семантиці арифметики з рухомою комою (включно з фактом NaN !== NaN) описані в стандарті IEEE 754. Логіка NaN включає:

  • Коли NaN бере участь у математичній операції (окрім бітових операцій), результат зазвичай також буде NaN. (Дивіться контрприклад нижче.)
  • Коли NaN є одним з операндів будь-якого відносного порівняння (>, <, >=, <=), результат завжди буде false.
  • NaN вважається нерівним (за допомогою ==, !=, === і !==) будь-якому іншому значенню – включно з іншим значенням NaN.

Крім цього, NaN є одним зі значень хибності в JavaScript.

Приклад

Перевірка на NaN

Щоб зрозуміти, чи є значення NaN, слід використовувати Number.isNaN() або isNaN() для якнайяснішого з'ясування, чи є значення NaN — або, оскільки NaN є єдиним нерівним самому собі значенням, можна виконати самопорівняння, отак: x !== x.

NaN === NaN; // false
Number.NaN === NaN; // false
isNaN(NaN); // true
isNaN(Number.NaN); // true
Number.isNaN(NaN); // true

function valueIsNaN(v) {
  return v !== v;
}
valueIsNaN(1); // false
valueIsNaN(NaN); // true
valueIsNaN(Number.NaN); // true

Проте зверніть увагу на різницю між isNaN() і Number.isNaN(): перший варіант поверне true, коли значення вже дорівнює NaN, або стане NaN після зведення до числа, натомість другий – поверне true лише коли значення вже є NaN:

isNaN("привіт, світе"); // true
Number.isNaN("привіт, світе"); // false

З тієї само причини використання значення BigInt викине помилку при використанні isNaN(), але не Number.isNaN():

isNaN(1n); // TypeError: Conversion from 'BigInt' to 'number' is not allowed.
Number.isNaN(1n); // false

Крім цього, одна частина методів масиву не може знайти NaN, а інша – може. А саме – ті, що шукають індекс (indexOf(), lastIndexOf()), не можуть знайти NaN, а ті, що шукають значення (includes()) – можуть:

const arr = [2, 4, NaN, 12];
arr.indexOf(NaN); // -1
arr.includes(NaN); // true

// Методи, що приймають коректно визначений предикат, завжди можуть знайти NaN
arr.findIndex((n) => Number.isNaN(n)); // 2

Більше інформації про NaN та його порівняння – на сторінці Перевірка на рівність та тотожність.

Помітно відмінні значення NaN

Є підстави для того, щоб NaN не було рівним самому собі. Можливо виробити два числа з рухомою точкою з різними двійковими представленнями, котрі обидва будуть NaN, тому що в кодуванні IEEE 754 будь-яке число з рухомою точкою з експонентою 0x7ff і ненульовою мантисою є NaN. У JavaScript маніпуляції бітового рівня можна виконати за допомогою типізованих масивів.

const f2b = (x) => new Uint8Array(new Float64Array([x]).buffer);
const b2f = (x) => new Float64Array(x.buffer)[0];
// Отримання байтового представлення NaN
const n = f2b(NaN);
const m = f2b(NaN);
// Змінити біт знаку, який не має значення для NaN
n[7] += 2 ** 7;
// n[0] += 2**7; для тупокінцевих процесорів
const nan2 = b2f(n);
console.log(nan2); // NaN
console.log(Object.is(nan2, NaN)); // true
console.log(f2b(NaN)); // Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 127]
console.log(f2b(nan2)); // Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 255]
// Змінити перший біт, який є найменш значущим бітом мантиси і не має значення для NaN
m[0] = 1;
// m[7] = 1; для тупокінцевих процесорів
const nan3 = b2f(m);
console.log(nan3); // NaN
console.log(Object.is(nan3, NaN)); // true
console.log(f2b(NaN)); // Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 127]
console.log(f2b(nan3)); // Uint8Array(8) [1, 0, 0, 0, 0, 0, 248, 127]

Тихе екранування NaN

NaN пролізає крізь усі математичні операції, тож зазвичай достатньо перевірити на NaN один раз – у кінці обчислення, щоб помітити помилку. Єдиний випадок, коли NaN тихо екранується – при піднесенні до степеня з показником степеня 0, що зразу повертає 1, без перевірки значення основи.

NaN ** 0 === 1; // true

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
NaN
Chrome Full support 1
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support 4
Opera Full support 4
Safari Full support 1
WebView Android Full support 1
Chrome Android Full support 18
Firefox for Android Full support 4
Opera Android Full support 10.1
Safari on iOS Full support 1
Samsung Internet Full support 1.0
Deno Full support 1.0
Node.js Full support 0.10.0

Дивіться також