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 |