Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Перевірка наявності властивості в об'єкті». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Наявність властивості перевіряють чотирма способами: оператором `in`, методом `hasOwnProperty()`, функцією `Object.hasOwn()` і порівнянням значення з `undefined`.** Різниця між ними в двох речах: чи враховують вони прототип і чи відрізняють відсутній ключ від ключа зі значенням `undefined`. Оператор `in` бачить і власні, і успадковані властивості, а `hasOwnProperty()` та `Object.hasOwn()` тільки власні. Перевірка `obj.key !== undefined` дивиться на значення, а не на ключ, тому вона найменш надійна. ```javascript const user = { name: 'Maria', age: 25 }; console.log('age' in user); // true console.log(Object.hasOwn(user, 'age')); // true console.log('city' in user); // false ``` **Ключове:** беріть `'key' in obj`, коли потрібні всі властивості разом з успадкованими, і `Object.hasOwn(obj, 'key')`, коли потрібні тільки власні.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Наявність властивості в об'єкті перевіряють оператором `in`, методом `hasOwnProperty()`, функцією `Object.hasOwn()` або порівнянням значення з `undefined`.** Ці способи не взаємозамінні: вони по-різному поводяться з прототипом і по-різному реагують на властивість, значення якої дорівнює `undefined`. ## Теорія ### TL;DR - `'key' in obj`, найуніверсальніший спосіб: повертає `true` і для власних, і для успадкованих від прототипу властивостей. - `obj.hasOwnProperty('key')` перевіряє тільки власні властивості та ігнорує прототип, це класика. - `Object.hasOwn(obj, 'key')`, сучасний стандарт з ES2022: та сама семантика, що й `hasOwnProperty`, але надійніша. - `obj.key !== undefined` перевіряє значення, а не ключ, тому дає хибний результат, коли значенням є `undefined`. - Коротке правило: потрібні всі властивості, беріть `in`; потрібні тільки власні, беріть `Object.hasOwn`. ### Швидкий приклад ```javascript const user = { name: 'Maria', age: 25 }; console.log('age' in user); // true console.log('city' in user); // false console.log(user.hasOwnProperty('age')); // true console.log(Object.hasOwn(user, 'city')); // false ``` ### Оператор in, найуніверсальніший спосіб ```javascript const user = { name: 'Maria', age: 25 }; console.log('age' in user); // true console.log('city' in user); // false ``` Оператор перевіряє, чи є **ключ** в об'єкті, разом з властивостями, успадкованими від прототипу. Ліворуч від `in` стоїть рядок або `Symbol`, праворуч, сам об'єкт. Приклад зі спадкуванням: ```javascript const person = { species: 'human' }; const user = Object.create(person); user.name = 'Maria'; console.log('species' in user); // true (успадковано) ``` Тут `species` немає безпосередньо в `user`, але воно є в його прототипі `person`, тому `in` повертає `true`. Саме тому `'toString' in {}` теж дає `true`: метод приходить з `Object.prototype`. ### Метод hasOwnProperty(), тільки власні властивості ```javascript const user = { name: 'Maria', age: 25 }; console.log(user.hasOwnProperty('age')); // true console.log(user.hasOwnProperty('city')); // false ``` На відміну від `in`, метод **ігнорує прототип** і перевіряє лише ті властивості, які реально задані в самому об'єкті. Приклад різниці: ```javascript const person = { species: 'human' }; const user = Object.create(person); user.name = 'Maria'; console.log('species' in user); // true console.log(user.hasOwnProperty('species')); // false ``` ### Object.hasOwn(), сучасний аналог hasOwnProperty ES2022 додав безпечніший і читабельніший спосіб: ```javascript const user = { name: 'Maria' }; console.log(Object.hasOwn(user, 'name')); // true console.log(Object.hasOwn(user, 'city')); // false ``` Працює так само, як `hasOwnProperty`, але не залежить від того, що відбувається всередині самого об'єкта. Два випадки, де `hasOwnProperty` ламається, а `Object.hasOwn` ні: ```javascript // 1. Об'єкт без прототипу: методу hasOwnProperty просто немає. const dict = Object.create(null); dict.token = 1; // dict.hasOwnProperty('token'); // TypeError console.log(Object.hasOwn(dict, 'token')); // true // 2. Власна властивість з таким самим іменем перекриває метод. const data = { hasOwnProperty: () => false, id: 7 }; console.log(data.hasOwnProperty('id')); // false, перевизначено console.log(Object.hasOwn(data, 'id')); // true ``` ### Перевірка на undefined, найпростіша, але не завжди точна ```javascript const user = { name: 'Maria' }; if (user.age !== undefined) { console.log('Властивість age є'); } else { console.log('Властивості age немає'); } ``` Мінус: якщо властивість **є**, але її значення дорівнює `undefined`, ви отримаєте хибне спрацювання. ```javascript const user = { age: undefined }; console.log(user.age !== undefined); // false, хоча ключ існує ``` Так само помилковою є скорочена перевірка `if (user.age)`: вона відкине `0`, `''`, `null` і `false`, які є цілком валідними значеннями. ### Порівняння способів | Спосіб | Що перевіряє | Враховує прототип | Надійність | | --- | --- | --- | --- | | `'key' in obj` | наявність ключа | Так | Відмінний вибір | | `obj.hasOwnProperty('key')` | тільки власні властивості | Ні | Класика | | `Object.hasOwn(obj, 'key')` | тільки власні властивості | Ні | Сучасний стандарт | | `obj.key !== undefined` | значення не `undefined` | Ні | Може бути хибним | > Щоб перевірити, чи є властивість в об'єкті, використовуйте `'key' in obj`, коли важливі всі властивості разом з успадкованими, або `Object.hasOwn(obj, 'key')`, коли потрібні **тільки власні**. ### Типові помилки - **Плутати наявність ключа і його значення.** `obj.key !== undefined` поверне `false` для властивості, яка існує зі значенням `undefined`. Перевіряйте ключ через `in` або `Object.hasOwn`. - **Скорочувати до `if (obj.key)`.** Значення `0`, `''`, `null`, `NaN` і `false` є хибними (falsy), тому існуючі властивості будуть «загублені». - **Забувати про прототип.** Оператор `in` бачить `toString`, `constructor` та інші успадковані властивості, тому для перевірки даних, що прийшли ззовні, беріть `Object.hasOwn`. - **Викликати `hasOwnProperty` на об'єкті з `Object.create(null)`.** Такий об'єкт не має прототипу, тому методу в нього немає і виклик кине `TypeError`. - **Довіряти `hasOwnProperty`, коли дані прийшли від користувача.** Вхідний JSON може містити власний ключ `hasOwnProperty` і перекрити метод. `Object.hasOwn` або `Object.prototype.hasOwnProperty.call(obj, key)` від цього захищені. - **Писати `in` з ім'ям змінної без лапок.** `key in obj` перевіряє значення змінної `key`, а `'key' in obj`, буквальний ключ `"key"`. Це різні перевірки.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.