Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Різниця між null та undefined». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**null** та **undefined** - обидва позначають "немає значення" в JavaScript. `undefined` рушій присвоює автоматично для неприсвоєних змінних та відсутніх властивостей. `null` це значення яке ти присвоюєш явно. ```javascript let x; // undefined - за замовчуванням let user = null; // null - явний вибір typeof undefined; // "undefined" typeof null; // "object" (спадковий баг) ``` **Ключове:** `undefined` сигналізує про неініціалізований стан; `null` про навмисну відсутність значення.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**null** та **undefined** - обидва позначають "немає значення" в JavaScript, але перший з'являється автоматично, а другий твій код встановлює явно. ## Теорія ### TL;DR - `undefined` JavaScript-рушій встановлює сам, коли змінна оголошена але не отримала значення - `null` це значення яке ти пишеш явно, щоб сказати "тут навмисно нічого" - Аналогія: `undefined` — порожня поштова скринька (місце є, листа немає); `null` — записка всередині: "навмисно порожньо" - Обидва є falsy, тому `if (!value)` спіймає обидва. Щоб розрізнити, використовуй суворе порівняння (`===`) - Правило: нехай `undefined` сигналізує про неініціалізований стан; `null` виставляй коли навмисно очищуєш значення ### Швидкий приклад ```javascript let uninitialized; // undefined за замовчуванням console.log(uninitialized); // undefined let cleared = "hello"; cleared = null; // явне скидання console.log(cleared); // null console.log(typeof uninitialized); // "undefined" console.log(typeof cleared); // "object" (спадковий баг з 1995-го) ``` `typeof null` повертає `"object"`, а не `"null"`. Це відомий баг JavaScript з 1995 року, який залишили щоб не зламати існуючий код. ### Ключова різниця `undefined` з'являється без твоїх дій. Оголоси змінну без присвоєння, зверни до відсутньої властивості об'єкта, виклич функцію без `return` — рушій підставить `undefined`. `null` твій код має встановити явно. Це сигнал: поле існує і воно навмисно порожнє. Різниця важлива в API та моделях даних, де "не існує" і "навмисно відсутнє" не одне й те саме. ### Коли використовувати - Змінна оголошена але ще не присвоєна: залиш як є, рушій подбає сам - Властивість об'єкта яку хочеш очистити: встанови `null` - JSON-відповідь API для відсутнього поля: використовуй `null` (`undefined` повністю випадає з `JSON.stringify`) - Функція без явного `return`: повертає `undefined` за замовчуванням - Дані сесії після виходу з системи: `req.user = null` — свідоме очищення, не пропущена ініціалізація ### Порівняльна таблиця | Аспект | undefined | null | |---|---|---| | Походження | Автоматично (рушій) | Явно (твоє присвоєння) | | `typeof` | `"undefined"` | `"object"` | | Нестроге порівняння `==` | Рівне `null` | Рівне `undefined` | | Строге порівняння `===` | Рівне лише собі | Рівне лише собі | | `JSON.stringify` | Властивість повністю випадає | Серіалізується як `"null"` | | Типове використання | Відсутні властивості, неініціалізовані змінні | Навмисно порожні поля, API-відповіді | ### Як рушій це обробляє Під час фази створення контексту виконання (execution context) V8 присвоює `undefined` кожній оголошеній змінній до запуску будь-якого коду. Саме тому читання `var` до рядка її присвоєння дає `undefined` замість помилки. `null` зберігається внутрішньо як тегований вказівник на порожній слот, через що `typeof null` повертає `"object"` замість `"null"`. ### Типові помилки **Перевірка через `==` коли потрібна точність** ```javascript let val = null; if (val == null) console.log('знайшли'); // true, але спіймає і undefined ``` `null == undefined` дає `true`. Якщо потрібно спіймати лише `null`, використовуй `val === null`. Якщо обидва прийнятні, `val == null` підійде — але пам'ятай що він спіймає і те, і інше. **Очікування що `typeof null` поверне `"null"`** ```javascript if (typeof foo === 'null') {} // ніколи не виконається ``` Для перевірки `null` завжди використовуй строге порівняння: `foo === null`. **`undefined` тихо зникає з JSON** ```javascript JSON.stringify({ a: undefined, b: null }); // Результат: '{"b":null}' ``` Це класична пастка для бекенд-команд. Ендпоінт повертає `{ field: undefined }` вважаючи що поле є, але клієнт отримує `{}`. Якщо поле має з'являтись у відповіді навіть порожнім, використовуй `null`. **Нестроге порівняння приховує реальний стан** ```javascript const data = { user: { profile: null } }; if (data.user.profile == undefined) { console.log('safe'); // спрацьовує, бо null == undefined } ``` Умова виконується і маскує факт що `profile` явно встановлено в `null`. Для точності використовуй `=== undefined`. ### Де зустрічається у реальному коді - React: `useState(null)` як початковий стан до завантаження даних - Express: `req.user = null` після виходу — явне очищення сесії - Redux: `state.error = null` для скидання помилки між запитами (зберігання `undefined` спричиняє застарілі повідомлення які не очищаються між dispatch-ами) - Node.js `fs.readFile`: параметр `err` у callback дорівнює `null` при успіху, не `undefined` - Lodash: `_.isNil(value)` перевіряє `null || undefined` коли обидва прийнятні ### Питання на співбесіді **Q:** Що повертає `typeof null` і чому? **A:** Повертає `"object"`. В оригінальній C-реалізації JavaScript `null` мав той самий тег типу що й об'єкти (0x00). Баг не виправили щоб не зламати існуючий код. **Q:** Як `null` та `undefined` поводяться в умовних виразах? **A:** Обидва є falsy, тому `if (!value)` спіймає обидва. Для розрізнення використовуй строге порівняння: `value === null` або `value === undefined`. **Q:** Що відбувається з `undefined` в JSON? **A:** `JSON.stringify` повністю прибирає властивості зі значенням `undefined`. `null` серіалізується як `"null"`. Тому API використовують `null` для відсутніх даних. **Q:** Що таке `void 0` і навіщо деякі мініфайкери його використовують? **A:** `void 0` завжди обчислюється як `undefined`. У старому JavaScript без strict mode глобальний `undefined` можна було перезаписати. `void 0` — безпечна альтернатива. В сучасному коді зі strict mode це не потрібно. **Q:** Як відрізнити відсутній ключ від ключа зі значенням `undefined`? **A:** Обидва повертають `undefined` при зверненні. Але `'key' in obj` дає `false` для відсутнього ключа і `true` для ключа явно встановленого в `undefined`. Ось як їх розрізнити. ## Приклади ### Базовий: автоматичне проти явного присвоєння ```javascript // undefined: рушій встановлює сам, без твоїх дій let username; console.log(username); // undefined function greet(name) { console.log(name); } greet(); // undefined - аргумент не передано // null: ти встановлюєш навмисно let currentUser = null; // ще не авторизований console.log(currentUser); // null ``` `undefined` з'являється коли щось відсутнє або не присвоєне. `null` є в коді лише тоді коли ти його туди поклав. ### Реальний сценарій: Express-обробник та JSON-відповідь ```javascript app.get('/user/:id', (req, res) => { const user = db.getUser(req.params.id); if (user === undefined) { // db.getUser нічого не знайшла — не те саме що "користувач без ролі" return res.status(404).json({ error: 'User not found' }); } // Явно очищуємо чутливе поле перед відправкою res.json({ ...user, passwordHash: null }); }); // GET /user/123 (є): { id: 123, name: "Alice", passwordHash: null } // GET /user/999 (нема): 404, { error: "User not found" } ``` `db.getUser` повертає `undefined` коли запис не знайдено. Відповідь встановлює `passwordHash` в `null`, щоб поле залишилось у JSON-відповіді але не містило чутливих даних.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.