Suggest an editImprove this articleRefine the answer for “Missing property vs undefined value”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**In JavaScript a property can be absent entirely, or it can exist while holding `undefined`, and the plain `obj.key === undefined` check cannot tell these two apart.** Reading a missing key also yields `undefined`, so the value alone carries no information about the key. The key itself is reported by the `in` operator or by `Object.hasOwn()`, and to capture exactly the "key exists, value is `undefined`" case you combine both checks. ```javascript const obj = { a: undefined }; const obj2 = {}; console.log(obj.a === undefined, obj2.a === undefined); // true true console.log('a' in obj, 'a' in obj2); // true false ``` **Key point:** check the value with `=== undefined`, check the key with `'key' in obj` or `Object.hasOwn(obj, 'key')`, and combine both conditions for an exact answer.Shown above the full answer for quick recall.Answer (EN)Image**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 | 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 === 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"`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.