Перевірка наявності властивості в об'єкті
У JavaScript є кілька способів перевірити, чи є в об'єкті та чи інша властивість, і кожен працює трохи по-різному. Різниця між ними в тому, чи враховується ланцюжок прототипів і чи можна обманути перевірку значенням undefined.
Теорія
TL;DR
'key' in objперевіряє наявність властивості, включно з успадкованими від прототипу.obj.hasOwnProperty('key')бачить тільки власні властивості, але метод можна перевизначити.Object.hasOwn(obj, 'key')(ES2022) це сучасна і безпечна замінаhasOwnProperty().obj.key !== undefinedперевіряє значення, а не наявність, тому помиляється на властивостях зі значеннямundefined.Reflect.has(obj, 'key')працює точно якin, зручний у метапрограмному коді.
Швидкий приклад
const user = { name: 'Alice', age: 25 };
console.log('name' in user); // true
console.log(Object.hasOwn(user, 'name')); // true
console.log('email' in user); // falseОператор in
Найпряміший і найнадійніший спосіб перевірити, що властивість взагалі існує.
const user = { name: 'Alice', age: 25 };
console.log('name' in user); // true
console.log('email' in user); // falseОператор враховує весь ланцюжок прототипів:
const person = { isHuman: true };
const user = Object.create(person);
user.name = 'Alice';
console.log('name' in user); // true, власна властивість
console.log('isHuman' in user); // true, успадкованаМетод hasOwnProperty()
Перевіряє тільки власні властивості, тобто ті, що реально належать самому об'єкту, а не прототипу.
const person = { isHuman: true };
const user = Object.create(person);
user.name = 'Alice';
console.log(user.hasOwnProperty('name')); // true
console.log(user.hasOwnProperty('isHuman')); // falseВикористовуйте його, коли треба переконатися, що властивість визначена в самому об'єкті, а не успадкована.
Обережно: якщо хтось перевизначив
hasOwnPropertyабо об'єкт створено черезObject.create(null)і прототипу в нього немає, метод краще викликати так:
Object.prototype.hasOwnProperty.call(user, 'name');Метод Object.hasOwn()
Сучасна версія hasOwnProperty зі стандарту ES2022, безпечніша, бо не залежить від ланцюжка прототипів самого об'єкта.
const user = { name: 'Alice' };
console.log(Object.hasOwn(user, 'name')); // true
console.log(Object.hasOwn(user, 'email')); // falseУ новому коді рекомендують брати саме Object.hasOwn() замість hasOwnProperty().
Перевірка через undefined
Простий, але не завжди безпечний спосіб:
const user = { name: 'Alice' };
console.log(user.name !== undefined); // true
console.log(user.email !== undefined); // falseПроблема в тому, що властивість може існувати, але мати значення undefined:
const user = { name: undefined };
console.log('name' in user); // true, властивість є
console.log(user.name !== undefined); // false, перевірка обманюєReflect.has() і порівняння способів
Ще один варіант, з Reflect API:
const user = { name: 'Alice' };
console.log(Reflect.has(user, 'name')); // true
console.log(Reflect.has(user, 'email')); // falseПрацює точно як in, але зручний у рефлексивному, метапрограмному коді, наприклад усередині пастки has у Proxy.
| Метод | Бачить успадковані | Тільки власні | Безпечний для будь-яких об'єктів | Приклад |
|---|---|---|---|---|
'key' in obj | так | ні | так | 'name' in user |
obj.hasOwnProperty('key') | ні | так | не завжди, метод можна перевизначити | user.hasOwnProperty('name') |
Object.hasOwn(obj, 'key') | ні | так | так | Object.hasOwn(user, 'name') |
obj.key !== undefined | не завжди | ні | так | user.name !== undefined |
| Мета | Найкращий спосіб | |||
| --- | --- | |||
| Перевірити будь-яку властивість, включно з прототипними | 'prop' in obj | |||
| Перевірити тільки власну властивість | Object.hasOwn(obj, 'prop') | |||
| Підтримка старих браузерів | obj.hasOwnProperty('prop') | |||
Перевірити, що значення не undefined | obj.key !== undefined, обережно |
Типові помилки
- Перевіряти наявність через
!== undefined. Властивість зі значеннямundefinedіснує, але така перевірка дастьfalse. - Використовувати
if (obj.count)як перевірку наявності. Значення0,'',falseіnullтеж falsy, тому наявне поле виглядатиме як відсутнє. - Викликати
hasOwnPropertyнапряму на об'єкті зObject.create(null). Прототипу немає, тому метод недоступний і будеTypeError; берітьObject.hasOwn(). - Плутати
inз перебором. Для масивівinперевіряє індекс, а не значення:1 in [10, 20]цеtrue, а20 in [10, 20]цеfalse. - Забувати про успадковані поля.
'toString' in {}цеtrue, бо метод приходить зObject.prototype. - Думати, що
?.замінює перевірку.user?.emailтільки захищає від помилки наnull, але не відрізняє відсутнє поле від поля зі значеннямundefined.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.