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
, тому що в кодуванні 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
Специфікації
Специфікація |
---|
ECMAScript Language Specification (ECMAScript) # sec-value-properties-of-the-global-object-nan |
Сумісність із браузерами
desktop | mobile | server | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
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 |