Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Звернення до неіснуючої властивості об'єкта». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Звернення до неіснуючої властивості не кидає помилку: вираз просто повертає `undefined`.** Помилка `TypeError` з'являється лише тоді, коли ви йдете далі по ланцюжку і намагаєтеся прочитати властивість уже в самого `undefined`. Безпечний доступ дає optional chaining `?.`, а значення за замовчуванням додає `??`. ```javascript const user = { name: 'Maria' }; console.log(user.age); // undefined, помилки немає console.log(user.address?.city); // undefined, теж без помилки console.log(user.address.city); // TypeError ``` **Ключове:** один рівень, це `undefined`, два рівні над відсутнім значенням, це `TypeError`, тому для вкладених даних використовуйте `?.`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Якщо звернутися до неіснуючої властивості об'єкта, помилки не буде, а результатом стане `undefined`.** Помилка виникає лише тоді, коли це `undefined` намагаються використати як об'єкт і прочитати вже його властивість. ## Теорія ### TL;DR - `obj.missing` повертає `undefined`, а не кидає виняток. - Так само поводиться динамічний доступ `obj[key]`. - `TypeError` з'являється на наступному кроці ланцюжка: `undefined.city`. - Безпечні способи: ручна перевірка через `&&`, optional chaining `?.`, значення за замовчуванням через `??`. - Щоб відрізнити «властивості немає» від «властивість дорівнює `undefined`», потрібні `in` або `hasOwnProperty`. ### Швидкий приклад ```javascript const user = { name: 'Maria' }; console.log(user.name); // "Maria" console.log(user.age); // undefined console.log(user.address); // undefined ``` JavaScript не кидає помилку, він просто повертає `undefined`. ### Чому повертається саме `undefined` Під час читання властивості рушій робить таке: 1. Перевіряє, чи є властивість **у самому об'єкті**. 2. Якщо **є**, повертає її значення. 3. Якщо **немає**, шукає далі по ланцюжку прототипів. 4. Якщо не знайшов ніде, повертає `undefined`. ```javascript user.hasOwnProperty('age'); // false user.age; // undefined ``` Це свідоме рішення мови: відсутня властивість, це не помилкова ситуація, а звичайний стан даних. ### Коли все-таки буде помилка Помилка з'явиться, якщо звернутися **далі** по ланцюжку: ```javascript console.log(user.address.city); // TypeError ``` Причина: `user.address`, це `undefined`, а в `undefined` **не можна запитувати властивості**. Текст помилки в браузері виглядає приблизно так: `TypeError: Cannot read properties of undefined (reading 'city')`. Те саме стосується `null`: обидва ці значення не мають обгортки-об'єкта, тому будь-яке читання властивості на них падає. ### Як безпечно читати вкладені властивості **Спосіб 1. Ручна перевірка.** ```javascript if (user.address && user.address.city) { console.log(user.address.city); } ``` **Спосіб 2. Optional chaining `?.` (сучасний підхід).** ```javascript console.log(user.address?.city); // undefined, але без помилки ``` Якщо ліворуч від `?.` стоїть `null` або `undefined`, JavaScript **зупиняє обчислення** всього ланцюжка і повертає `undefined`. **Спосіб 3. Значення за замовчуванням через `??`.** ```javascript console.log(user.address?.city ?? 'Не вказано'); // "Не вказано" ``` ### Динамічний доступ і перевірка наявності Через квадратні дужки поведінка та сама: ```javascript const key = 'email'; console.log(user[key]); // undefined, якщо властивості немає ``` Проблема в тому, що `undefined` повертається і тоді, коли властивість існує, але її значення дорівнює `undefined`. Щоб відрізнити ці два випадки, потрібні окремі перевірки: ```javascript const account = { email: undefined }; account.email; // undefined 'email' in account; // true, властивість є account.hasOwnProperty('email'); // true, і вона власна Object.hasOwn(account, 'email'); // true, сучасний варіант ``` `in` враховує і властивості з прототипу, а `hasOwnProperty` та `Object.hasOwn` лише власні. ### Підсумкові таблиці | Ситуація | Результат | Пояснення | | --- | --- | --- | | `user.age` | `undefined` | властивості немає | | `user.age.city` | `TypeError` | `undefined` не є об'єктом | | `'age' in user` | `false` | перевірка наявності властивості | | `user.hasOwnProperty('age')` | `false` | перевірка лише власних властивостей | | `user.name ?? 'немає'` | `'Maria'` | повертається значення | | `user.age ?? 'немає'` | `'немає'` | підставляється значення за замовчуванням | | Поведінка | Що відбувається | | --- | --- | | `obj.missing` | повертає `undefined` | | Помилки немає | навіть якщо властивості не існує | | Помилка з'являється | під час спроби піти глибше (`undefined.city`) | | Рішення | використати `?.` або `??` | Приклад для закріплення: ```javascript const user = { name: 'Maria' }; console.log(user.age); // undefined console.log(user.age?.value); // undefined (без помилки) console.log(user.age ?? 'немає'); // "немає" console.log(user.age.value); // TypeError ``` ### Типові помилки - **Розраховують на помилку там, де її немає.** Одруківка в назві властивості тихо дає `undefined`, і баг спливає значно пізніше, уже в іншому місці коду. - **Читають глибокий ланцюжок без `?.`.** Дані з API часто приходять неповними, і `data.user.profile.avatar` падає на першому ж відсутньому рівні. - **Ставлять `?.` лише в кінці ланцюжка.** `user.address?.city` не рятує, якщо `undefined` може бути сам `user`. Тоді потрібно `user?.address?.city`. - **Плутають «немає властивості» і «значення `undefined`».** Порівняння `obj.key === undefined` не розрізняє ці випадки, для цього є `in` та `Object.hasOwn`. - **Викликають неіснуючий метод.** `obj.doSomething()` кидає `TypeError: obj.doSomething is not a function`, бо викликати `undefined` не можна. Безпечна форма, це `obj.doSomething?.()`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.