Check if a key exists in a JavaScript object (7 ways + tested output)

Tech reviewed: Deepak Prasad
Check if a key exists in a JavaScript object (7 ways + tested output)

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: all examples in this tutorial were run with Node.js v20.18.2, and the output shown below each snippet is its exact console output.


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"));
text
true
false

Inherited keys are excluded, unlike in:

javascript
console.log("toString" in {});
console.log(Object.hasOwn({}, "toString"));
text
true
false

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);
text
true true false

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);
text
true true false

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"));
text
true false

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"),
);
text
true true true true false

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"));
text
true
false

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"));
text
true
false

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"));
text
true
true
false

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"),
);
text
true true

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));
text
true

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));
text
true

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),
);
text
true true true

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"));
text
true true true

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"));
text
true false true false

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));
text
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)));
text
true
false

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);
text
true false

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 over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, …

  • Red Hat Certified System Administrator in Red Hat OpenStack
  • Certified Kubernetes Application Developer (CKAD)
  • Red Hat Certified Specialist in Ansible Automation
  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security