Missing property vs undefined value
To tell a property that holds undefined from a property the object does not have, check for the key with the in operator or Object.hasOwn() instead of comparing the value with undefined. These are two different situations that read back as the same value, so a single comparison is not enough.
Theory
TL;DR
obj.key === undefinedonly checks the value and returnstrueboth for an existing key holdingundefinedand for a key that is not there.'key' in objchecks for the key itself, including properties inherited from the prototype.Object.hasOwn(obj, 'key')does the same for own properties and is the safer modern option.- The exact "the property exists but is
undefined" check is'key' in obj && obj.key === undefined. - Reading a missing key does not throw, it simply returns
undefined, which is why silent bugs are so common here.
Quick example
const obj = { a: undefined };
const obj2 = {};
// The value is identical in both cases.
console.log(obj.a); // undefined
console.log(obj2.a); // undefined
// The keys are not.
console.log('a' in obj); // true
console.log('a' in obj2); // falseChecking that a property exists
First, a reminder of how you check whether a key is present in an object:
'key' in obj // true if the property exists (even when it is undefined)
Object.hasOwn(obj, 'key') // the same, only safer and about own properties only'key' in obj says nothing about what the property is equal to, it only verifies that the key exists in the object. The difference between the two is the prototype: in also sees inherited properties, while Object.hasOwn() sees only the ones stored on the object itself.
A property that exists and equals undefined
Here is an object where the key is declared explicitly and holds undefined:
const obj = {
a: undefined
};And here is an object that has no such key at all:
const obj2 = {};When you read the property they behave identically, even though the underlying structures differ: in the first case the key a really is in the object's list of keys, in the second it is not.
The difference in practice
console.log('a' in obj); // true (the property exists)
console.log('a' in obj2); // false (the property is missing)
console.log(obj.a === undefined); // true
console.log(obj2.a === undefined); // true (both are true)The problem is that the simple obj.a === undefined check does not distinguish "the property is missing" from "the property exists but is undefined". It shows up wherever the key carries meaning of its own: a partial update where { nickname: undefined } means "clear this field" while {} means "leave it alone".
The fix: combine the checks
To know for sure that the property exists and equals undefined, you need both conditions:
if ('a' in obj && obj.a === undefined) {
console.log('The property exists, but its value is undefined');
}Here 'a' in obj checks for the key, and obj.a === undefined checks the value. If inherited properties are not what you want, replace the first operand with Object.hasOwn(obj, 'a').
Example: all the cases side by side
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, undefinedOnly for c does in return false. For a it returns true, meaning the key is there, even though its value is undefined.
Summary table
| Check | What it does | Distinguishes a missing key? |
|---|---|---|
obj.key === undefined | checks the value only | No |
'key' in obj | checks whether the key exists | Yes |
'key' in obj && obj.key === undefined | checks both conditions | Yes |
Object.hasOwn(obj, 'key') | the modern counterpart of in for own properties | Yes |
Common mistakes
- Treating
obj.key === undefinedas an existence check. It istrueboth for a missing key and for a key holdingundefined, so it answers a different question. - Writing
if (obj.key)instead of a comparison. The values0,'',null,NaNandfalseare falsy, so an existing property is read as missing. - Forgetting that
insees the prototype.'toString' in {}istruebecause the method comes fromObject.prototype. For data that arrived from outside, useObject.hasOwn(). - Confusing
undefinedwithnull.nullis an explicit "empty" value, its key exists, andobj.key === undefinedreturnsfalsefor it. - Relying on
JSON.stringify()for the check. It drops properties whose value isundefined, so{ a: undefined }and{}both serialise to the same{}string. - Writing
key in objwithout quotes. That checks the value of the variablekey, not the literal key"key".
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.