Skip to main content

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 === undefined only checks the value and returns true both for an existing key holding undefined and for a key that is not there.
  • 'key' in obj checks 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

javascript
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); // false

Checking that a property exists

First, a reminder of how you check whether a key is present in an object:

javascript
'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:

javascript
const obj = { a: undefined };

And here is an object that has no such key at all:

javascript
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

javascript
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:

javascript
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

javascript
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

Only for c does in return false. For a it returns true, meaning the key is there, even though its value is undefined.

Summary table

CheckWhat it doesDistinguishes a missing key?
obj.key === undefinedchecks the value onlyNo
'key' in objchecks whether the key existsYes
'key' in obj && obj.key === undefinedchecks both conditionsYes
Object.hasOwn(obj, 'key')the modern counterpart of in for own propertiesYes

Common mistakes

  • Treating obj.key === undefined as an existence check. It is true both for a missing key and for a key holding undefined, so it answers a different question.
  • Writing if (obj.key) instead of a comparison. The values 0, '', null, NaN and false are falsy, so an existing property is read as missing.
  • Forgetting that in sees the prototype. 'toString' in {} is true because the method comes from Object.prototype. For data that arrived from outside, use Object.hasOwn().
  • Confusing undefined with null. null is an explicit "empty" value, its key exists, and obj.key === undefined returns false for it.
  • Relying on JSON.stringify() for the check. It drops properties whose value is undefined, so { a: undefined } and {} both serialise to the same {} string.
  • Writing key in obj without quotes. That checks the value of the variable key, not the literal key "key".

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.