Check if a key exists in a JavaScript object: 7 reliable patterns

Check if key exists in object JavaScript: Object.hasOwn, in, hasOwnProperty, Object.keys, getOwnPropertyNames, symbols, Reflect.ownKeys—with example console output and own vs inherited rules.

Published

Updated

Read time 7 min read

Reviewed byDeepak Prasad

Check if a key exists in a JavaScript object: 7 reliable patterns

Before you read a property on a plain object, it helps to know whether that key actually exists—as an own property, on the prototype chain, or not at all—because reading a missing key quietly yields undefined and hides typos. This guide compares seven practical approaches (Object.hasOwn, in, hasOwnProperty, Object.keys, Object.getOwnPropertyNames, Object.getOwnPropertySymbols, and Reflect.ownKeys) so you can match the API to your intent. When you only care about enumerable string keys for serialization-style work, pairing Object.keys with ideas from looping object keys in JavaScript is also common.

Tested on: Node.js v20.18.2. Short notes after each snippet describe the values you should see in the console.


Quick reference

Use this table when you need javascript check if object has key or js check if key exists at a glance.

Need Use
Own string/symbol key (recommended default) Object.hasOwn(obj, key)
Own or inherited key key in obj
Only enumerable own string keys Object.keys(obj).includes(key) (or loop)
All own string keys (incl. non-enumerable) Object.getOwnPropertyNames(obj).includes(key)
Own symbol keys Object.getOwnPropertySymbols(obj).includes(sym)
Everything own (strings + symbols, any enumerability) Reflect.ownKeys(obj).includes(keyOrSymbol)

1. Object.hasOwn (modern default for “javascript object has key”)

Object.hasOwn(obj, prop) (ES2022) asks whether prop is an own property of obj—not inherited. MDN recommends it over calling obj.hasOwnProperty(...) on unknown objects.

javascript
const car = { make: "Toyota", model: "Corolla" };

console.log(Object.hasOwn(car, "make"));
console.log(Object.hasOwn(car, "year"));
Output

You should see true then falsemake is own, year is absent.

Inherited keys are excluded, unlike in:

javascript
console.log("toString" in {});
console.log(Object.hasOwn({}, "toString"));
Output

in reports true (inherited toString), while Object.hasOwn reports false for an empty object’s own keys.


2. The in operator (own or prototype chain)

prop in obj is true if prop exists on obj or its prototype chain—useful when inheritance matters, awkward for plain “dictionary” objects where inherited names like toString can surprise you.

javascript
const book = { title: "1984", author: "George Orwell" };

console.log("title" in book, "author" in book, "published" in book);
Output

You should see three booleans: true, true, then false for the missing published key.

Nested object: in still checks one object at a time.

javascript
const company = {
  name: "Innovatech",
  department: { name: "Research", head: "Alice Johnson" },
};

console.log("name" in company, "head" in company.department, "budget" in company.department);
Output

Expect true for name on company, true for head on department, and false for budget (not defined on that nested object).

Prototype example (tested): if the key lives on the prototype, in is true but Object.hasOwn is false.

javascript
const withProto = Object.create({ budget: 999 });
withProto.name = "X";

console.log("budget" in withProto, Object.hasOwn(withProto, "budget"));
Output

You should see true then false: budget exists via the prototype, but it is not an own property of withProto.


3. hasOwnProperty (legacy instance method)

obj.hasOwnProperty("key") matches Object.hasOwn for ordinary objects, but an object can override hasOwnProperty as a data field—so libraries often use Object.prototype.hasOwnProperty.call(obj, "key"). Prefer Object.hasOwn when available.

javascript
const university = {
  name: "State University",
  faculty: {
    arts: { head: "Dr. Emily Rose" },
    science: { head: "Dr. John Doe" },
  },
};

console.log(
  university.hasOwnProperty("name"),
  university.hasOwnProperty("faculty"),
  university.faculty.hasOwnProperty("arts"),
  university.faculty.arts.hasOwnProperty("head"),
  university.faculty.hasOwnProperty("budget"),
);
Output

The log prints five booleans ending in false only for the non-existent faculty.budget key.


4. Object.keys + includes (enumerable string keys only)

Object.keys(obj) returns only own enumerable string keys. It does not list symbols or non-enumerable own keys.

javascript
const person = { name: "Sarah", age: 25 };

console.log(Object.keys(person).includes("name"));
console.log(Object.keys(person).includes("occupation"));
Output

You should see true for name and false for occupation.

Nested:

javascript
const product = { id: 101, details: { price: 29.99, stock: 120 } };

console.log(Object.keys(product.details).includes("price"));
console.log(Object.keys(product.details).includes("discount"));
Output

Expect true for price and false for discount.


5. Object.getOwnPropertyNames + includes (all string own keys)

Object.getOwnPropertyNames(obj) lists all own string property names, enumerable or not—useful when a key was defined with enumerable: false.

javascript
const vehicle = { make: "Honda" };
Object.defineProperty(vehicle, "hiddenFeature", {
  value: "secret",
  enumerable: false,
});

console.log(Object.getOwnPropertyNames(vehicle).includes("make"));
console.log(Object.getOwnPropertyNames(vehicle).includes("hiddenFeature"));
console.log(Object.keys(vehicle).includes("hiddenFeature"));
Output

Three lines: true for make, true for the non-enumerable hiddenFeature via getOwnPropertyNames, and false when using Object.keys (non-enumerable keys are omitted).

Nested:

javascript
const company = { name: "Tech Corp", department: { name: "Development" } };
Object.defineProperty(company.department, "internalCode", {
  value: "X123",
  enumerable: false,
});

console.log(
  Object.getOwnPropertyNames(company.department).includes("name"),
  Object.getOwnPropertyNames(company.department).includes("internalCode"),
);
Output

Both checks print truename is enumerable; internalCode is still listed by getOwnPropertyNames.


6. Object.getOwnPropertySymbols + includes

For symbol-keyed own properties:

javascript
const user = { name: "John", [Symbol("password")]: "12345" };
const symbols = Object.getOwnPropertySymbols(user);
const pwdSym = symbols.find((s) => s.description === "password");

console.log(symbols.includes(pwdSym));
Output

You should see true once the located symbol is found in the symbol list.

Nested:

javascript
const settings = { level: 1, options: { [Symbol("secret")]: "hidden_value" } };
const optionSymbols = Object.getOwnPropertySymbols(settings.options);
const secSym = optionSymbols.find((s) => s.description === "secret");

console.log(optionSymbols.includes(secSym));
Output

Again true when the matching symbol reference is in the array returned for the nested object.


7. Reflect.ownKeys + includes (strings and symbols, any enumerability)

Reflect.ownKeys(obj) returns all own keys—strings and symbols—regardless of enumerability. It still does not walk the prototype chain (unlike in).

javascript
const company = { name: "Tech Solutions", department: { employees: 250 } };
Object.defineProperty(company.department, "budget", {
  value: 1_000_000,
  enumerable: false,
});
const departmentSymbols = Symbol("internalCode");
company.department[departmentSymbols] = "Dept01";

const departmentKeys = Reflect.ownKeys(company.department);

console.log(
  departmentKeys.includes("employees"),
  departmentKeys.includes("budget"),
  departmentKeys.includes(departmentSymbols),
);
Output

One line with three true values: enumerable employees, non-enumerable budget, and the symbol key are all “own” per Reflect.ownKeys.


The seven methods above cover plain objects, but real code runs into special cases where the obvious check gives a misleading result. This section collects the gotchas and related data structures you are most likely to hit—keys whose value is undefined, Map and Set collections, nested lookups, batch checks, and arrays—so the right tool is clear when an object check is not enough.

undefined still means “key exists” for own properties

A common mistake is testing obj.key === undefined to decide if a key is missing. But a key can exist and hold the value undefined, so a value check cannot tell “absent” from “present but undefined.” The existence methods report the key correctly:

javascript
const o = { a: undefined };

console.log("a" in o, Object.hasOwn(o, "a"), Object.keys(o).includes("a"));
Output

All three checks print true even though the value stored at a is undefined.

Map / Set — use has, not object key rules

A Map or Set is not a plain object, and in / Object.hasOwn do not inspect their entries. Each collection ships a purpose-built has() method—Map.has(key) for keys and Set.has(value) for membership—which is the correct (and faster) way to test presence:

javascript
const m = new Map([["id", 1]]);
const s = new Set(["x"]);

console.log(m.has("id"), m.has("missing"), s.has("x"), s.has("y"));
Output

You should see true, false, true, false in order—Map.has / Set.has mirror membership without touching object-key helpers.

Optional chaining for nested values (not a key-exists API)

Optional chaining (?.) safely reads down a nested path without throwing a TypeError on a missing level, but it checks values, not keys—a present key holding undefined and a missing key both yield undefined:

javascript
const company = { department: { name: "R&D" } };

console.log(String(company?.department?.budget));
Output

The expression stringifies to "undefined" (the string), because the missing path yields the value undefined.

Combine it with in / Object.hasOwn on the final object when you must distinguish missing vs undefined.

Check several keys at once

When you need to confirm that all required keys are present—for example validating a config object—pair Array.prototype.every() with Object.hasOwn to fold the per-key checks into a single boolean:

javascript
const cfg = { host: "db", port: 5432 };

console.log(["host", "port"].every((k) => Object.hasOwn(cfg, k)));
console.log(["host", "ssl"].every((k) => Object.hasOwn(cfg, k)));
Output

The first every is true (both keys exist); the second is false because ssl is missing.

Arrays: in checks indices, not values

Arrays are objects whose keys are numeric indices, so in tests whether an index exists, never whether a value is in the array. Use includes() to search by value and reserve in for “does this position exist”:

javascript
const fruits = ["Apple", "Banana"];
console.log(0 in fruits, 2 in fruits);
Output

Index 0 exists (true); index 2 does not (false)—this is not the same as searching for "Apple" in values.


Summary

  • Use Object.hasOwn for the common “js check if object has key” case: own properties only, safe and clear.
  • Use in when inheritance should count; remember prototype pollution surprises on plain objects.
  • Use Object.keys only when enumerable string keys are what you mean; use getOwnPropertyNames / Reflect.ownKeys when non-enumerable or symbol keys matter.
  • Reflect.ownKeys, Object.keys, and getOwnPropertyNames all enumerate own keys of the target object—they do not replace in for inherited properties.

References

MDN reference pages for each API used in the seven patterns above.


Frequently Asked Questions

1. What is the best way to check if a key exists in a JavaScript object?

For own string keys, prefer Object.hasOwn(obj, key) in modern engines—it is static, readable, and avoids rare bugs where an object shadows hasOwnProperty. Use the in operator when you intentionally need the prototype chain (for example checking inherited methods).

2. What is the difference between in and Object.hasOwn in JavaScript?

in returns true if the property exists anywhere on the prototype chain. Object.hasOwn returns true only for own properties (string or symbol), including keys whose value is undefined.

3. Does Object.keys tell me if a key exists?

Object.keys lists only own enumerable string keys. A non-enumerable own property or a symbol key will not appear, so includes on Object.keys can wrongly suggest the key is missing.

4. How do I check if a nested key exists without a TypeError?

Use optional chaining (obj?.a?.b) combined with a presence check, or validate each level before descending. in and hasOwn only apply to the object you pass in—you must walk the path for deep keys.

5. How do I check for a key in a Map or Set in JavaScript?

Use Map.prototype.has(key) for Map keys, and Set.prototype.has(value) for Set membership—they are purpose-built and avoid treating the collection as a plain object.

6. If a property exists but its value is undefined, is the key still there?

Yes for own properties: Object.hasOwn and hasOwnProperty still return true, and in returns true if the key exists on the object or prototype. Only checking value === undefined cannot distinguish missing from present-but-undefined.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …