Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке nan у JavaScript?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**NaN** (Not-a-Number) - це числове значення в JavaScript, яке сигналізує про недійсний результат математичної операції, наприклад `0 / 0` або парсинг нечислового рядка. ```javascript NaN === NaN; // false typeof NaN; // "number" Number.isNaN(NaN); // true ``` **Ключове:** для перевірки використовуй `Number.isNaN()`, а не `=== NaN` і не глобальний `isNaN()`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**NaN** - це спеціальне числове значення в JavaScript, яке сигналізує про недійсний результат математичної операції, наприклад ділення нуля на нуль або парсинг нечислового рядка. ## Теорія ### TL;DR - NaN означає "Not-a-Number," але його тип все одно `"number"` (`typeof NaN === "number"`) - Уяви отруєну пігулку: один NaN у розрахунку заражає всі наступні результати - `NaN !== NaN` завжди `false`. Не баг, це специфікація - `Number.isNaN()` - правильний спосіб перевірки. Глобальний `isNaN()` спочатку перетворює рядки і дає хибні результати ### Швидкий приклад ```javascript console.log(0 / 0); // NaN console.log(typeof NaN); // "number" console.log(NaN === NaN); // false console.log(Number.isNaN(NaN)); // true const result = "abc" * 5; console.log(result + 10); // NaN (розповсюджується) ``` NaN заражає. Будь-яка арифметика з NaN повертає NaN. Один поганий вхід може зруйнувати цілий ланцюг обчислень без жодної помилки. ### Чому NaN !== NaN Стандарт IEEE 754 визначає NaN як "невпорядковане" значення. Два недійсних результати можуть походити від абсолютно різних операцій: `0/0` і `Math.sqrt(-1)` - обидва NaN, але це різні типи недійсності. Тому стандарт каже: рівність з NaN завжди повертає `false`. Це змушує явно виявляти його, а не випадково довіряти. V8 зберігає NaN як бітовий патерн `0x7FF8000000000000`. Оператор `===` порівнює бітові патерни, і будь-яке порівняння з NaN за специфікацією повертає `false`. Без винятків. ### Коли використовувати Number.isNaN() - Парсинг введення: перевіряй `Number.isNaN()` перед будь-яким розрахунком з даними від користувача - API відповіді: заміни NaN на `null` перед відправкою JSON (`JSON.stringify` все одно конвертує NaN у `null`, що може непомітно зламати математику на клієнті) - Агрегація масивів: відфільтруй NaN перед викликом `.reduce()` - Де б ти не використовував глобальний `isNaN()`: заміни його на `Number.isNaN()` ### Як JavaScript створює NaN Недійсні числові операції породжують NaN: ділення нуля на нуль, квадратний корінь з від'ємного числа, парсинг нечислового рядка через `Number()` або `parseInt()`. Після цього будь-яка арифметика з NaN автоматично повертає NaN. Зараження відбувається само по собі. ### Поширені помилки **Порівняння через ===** ```javascript if (result === NaN) { /* ніколи не виконається */ } ``` NaN не дорівнює нічому, навіть собі. Рішення: `Number.isNaN(result)`. **Використання глобального isNaN() на рядках** ```javascript isNaN("hello"); // true (перетворено в NaN) isNaN("123abc"); // true (перетворено в NaN) isNaN("123"); // false (перетворено в 123) ``` Глобальний `isNaN()` спочатку конвертує аргумент. Він не може відрізнити "це насправді NaN" від "цей рядок просто не парситься як число." Використовуй `Number.isNaN(Number(value))`, коли потрібні обидві перевірки. **NaN в JSON** ```javascript JSON.stringify({ score: NaN }); // {"score":null} ``` У JSON немає NaN. Серіалізація конвертує його у `null`. Якщо клієнт прочитає цей `null` і спробує робити математику, результати будуть неправильними без жодної помилки. Очищуй дані перед stringify. **NaN отруює Math.min / Math.max** ```javascript Math.min(1, NaN, 3); // NaN ``` Один NaN отруює весь агрегат. Спочатку відфільтруй масив. ### Де зустрічається в реальних проєктах - React / Formik: `Number.isNaN()` у валідаторах числових полів перед відправкою форми - Express: парсинг `req.query.age` через `parseInt()`, перевірка NaN перед запитами до бази - D3.js: фільтрація NaN з масивів даних графіків перед обчисленням шкал - Lodash: `_.isNaN()` як зручна обгортка в утилітах ### Питання на співбесіді **Q:** Чому `typeof NaN === "number"`, якщо NaN не є дійсним числом? **A:** Система типів JavaScript слідує IEEE 754. NaN - це частина простору чисел з плаваючою точкою, просто недійсний стан усередині нього. Позначка типу технічно правильна. **Q:** Яка різниця між `isNaN()` і `Number.isNaN()`? **A:** Глобальний `isNaN()` перетворює аргумент, тому `isNaN("foo")` повертає `true`. `Number.isNaN()` пропускає перетворення і повертає `true` тільки для самого NaN, тому `Number.isNaN("foo")` повертає `false`. **Q:** Як обробити NaN в array reduce? **A:** Фільтруй перед reduce: `.filter(v => !Number.isNaN(v))`. Або захисти callback з fallback значенням. **Q:** Що робить JSON.stringify з NaN? **A:** Конвертує NaN у `null`. У JSON немає представлення NaN. Завжди очищуй дані перед серіалізацією. **Q:** (Senior) V8 зберігає NaN як `0x7FF8000000000000`. Чому `+NaN === NaN` все одно повертає `false`? **A:** Унарний `+` повертає той самий бітовий патерн. Але IEEE 754 вказує, що будь-яке порівняння з NaN повинно повертати `false` незалежно від цього. Це навмисно, щоб недійсні значення не могли випадково пройти перевірки рівності. ## Приклади ### Парсинг введення користувача ```javascript const userAge = "25a"; const age = parseInt(userAge, 10); // NaN if (Number.isNaN(age)) { console.log("Невалідний вік"); // виконується } else { console.log(`Вік через 5 років: ${age + 5}`); } // Output: "Невалідний вік" ``` `parseInt` зупиняється на першому нечисловому символі і повертає NaN. Перевіряй до розрахунків, а не після. ### Виправлення NaN в array reduce ```javascript const prices = ["$10", "20", "abc"]; // Без виправлення: NaN отруює суму const broken = prices.reduce((sum, p) => sum + Number(p), 0); console.log(broken); // NaN // З виправленням: спочатку фільтруй недійсні значення const total = prices .map(p => Number(p.replace("$", ""))) .filter(v => !Number.isNaN(v)) .reduce((sum, v) => sum + v, 0); console.log(total); // 30 ``` Саме такий патерн ламав продакшен дашборди, де одне погане значення з API перетворювало цілий блок статистики на NaN. Виправлення займає один рядок.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.