Відсутня властивість чи значення undefined
Щоб відрізнити властивість зі значенням undefined від властивості, якої в об'єкті немає, перевіряють наявність ключа оператором in або Object.hasOwn(), а не порівнюють значення з undefined. Це дві різні ситуації, які дають однакове значення при читанні, тому одного порівняння недостатньо.
Теорія
TL;DR
obj.key === undefinedперевіряє лише значення і повертаєtrueі для наявного ключа зі значеннямundefined, і для ключа, якого немає.'key' in objперевіряє наявність ключа, разом з успадкованими від прототипу властивостями.Object.hasOwn(obj, 'key')робить те саме для власних властивостей і є безпечнішим сучасним варіантом.- Точна перевірка «властивість є, але дорівнює
undefined»:'key' in obj && obj.key === undefined. - Читання відсутнього ключа не кидає помилку, воно просто повертає
undefined, тому мовчазні баги тут дуже типові.
Швидкий приклад
const obj = { a: undefined };
const obj2 = {};
// Значення однакове в обох випадках.
console.log(obj.a); // undefined
console.log(obj2.a); // undefined
// А ключі різні.
console.log('a' in obj); // true
console.log('a' in obj2); // falseПеревірка наявності властивості
Спочатку згадаймо, як перевірити, чи є ключ в об'єкті:
'key' in obj // true, якщо властивість є (навіть якщо undefined)
Object.hasOwn(obj, 'key') // те саме, тільки безпечніше і лише про власні властивостіОператор 'key' in obj не говорить, чому дорівнює властивість, він лише перевіряє, що ключ існує в об'єкті. Різниця між ними в прототипі: in бачить і успадковані властивості, а Object.hasOwn() тільки ті, що лежать у самому об'єкті.
Властивість є, але дорівнює undefined
Ось об'єкт, у якому ключ явно заданий і має значення undefined:
const obj = {
a: undefined
};А ось об'єкт, у якому такого ключа немає зовсім:
const obj2 = {};З погляду читання властивості вони поводяться однаково, хоча всередині це різні структури: у першому випадку ключ a реально є у списку ключів об'єкта, у другому його там немає.
Різниця на практиці
console.log('a' in obj); // true (властивість є)
console.log('a' in obj2); // false (властивості немає)
console.log(obj.a === undefined); // true
console.log(obj2.a === undefined); // true (обидва дають true)Проблема в тому, що проста перевірка obj.a === undefined не відрізняє «відсутність властивості» від «властивість є, але undefined». Це помітно там, де ключ несе сенс сам по собі: часткове оновлення запису, де { nickname: undefined } означає «стерти значення», а {} означає «не чіпати поле».
Рішення: комбінувати перевірки
Щоб точно дізнатися, що властивість є і дорівнює undefined, потрібні обидві умови:
if ('a' in obj && obj.a === undefined) {
console.log('Властивість є, але значення undefined');
}Тут 'a' in obj перевіряє наявність ключа, а obj.a === undefined перевіряє значення. Якщо успадковані властивості вам не потрібні, замініть перший доданок на Object.hasOwn(obj, 'a').
Приклад: порівняння всіх випадків
const data = {
a: undefined,
b: 10
};
console.log('a' in data, data.a); // true, undefined
console.log('b' in data, data.b); // true, 10
console.log('c' in data, data.c); // false, undefinedТільки для c оператор in поверне false. Для a він дає true, тобто ключ є, навіть якщо його значення undefined.
Підсумкова таблиця
| Перевірка | Що робить | Відрізняє наявність ключа? |
|---|---|---|
obj.key === undefined | перевіряє тільки значення | Ні |
'key' in obj | перевіряє, чи є ключ | Так |
'key' in obj && obj.key === undefined | перевіряє обидві умови | Так |
Object.hasOwn(obj, 'key') | сучасний аналог in для власних властивостей | Так |
Типові помилки
- Вважати
obj.key === undefinedперевіркою наявності. Вона даєtrueі для відсутнього ключа, і для ключа зі значеннямundefined, тобто відповідає на інше питання. - Писати
if (obj.key)замість порівняння. Значення0,'',null,NaNіfalseє falsy, тому наявна властивість буде сприйнята як відсутня. - Забувати, що
inбачить прототип.'toString' in {}повертаєtrue, бо метод приходить зObject.prototype. Для даних, що прийшли ззовні, берітьObject.hasOwn(). - Плутати
undefinedіnull.nullє явним значенням «порожньо», його ключ існує, іobj.key === undefinedдля нього повернеfalse. - Покладатися на
JSON.stringify()для перевірки. Він викидає властивості зі значеннямundefined, тому{ a: undefined }і{}перетворюються на однаковий рядок{}. - Писати
key in objбез лапок. Тоді перевіряється значення змінноїkey, а не буквальний ключ"key".
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.