Object.hasOwn()

A static replacement for a method call that could always be broken by the object being tested. That is the whole reason it exists.

Object static methodES2022Live demo
Common call
Object.hasOwn(obj, key)
Returns
boolean
Replaces
Object.prototype.hasOwnProperty.call(obj, key)
Watch out
own properties ONLY — inherited ones return false
Object.hasOwn(objectobject — The object to inspect. null and undefined throw TypeError.type: object · required, keykey — The property key. Non-symbol values are coerced to strings, so 1 and "1" are the same key.type: string | symbol · required)
→ boolean

Demo

Live evaluation
Try:
Inputs
jsonstringa JSON object
keystringproperty name
Output
Object.hasOwn(JSON.parse('{"a":1}'), 'a')
true

The third case is the point of the method: toString exists on every object via the prototype chain, and hasOwn reports FALSE because it is not an OWN property. The `in` operator would say true. The fourth case shows why this beats a truthiness check — the property exists but its value is null, so obj.a would be falsy while hasOwn correctly reports that the key is there. That distinction matters whenever null or 0 or empty string are legitimate values.

Parameters

NameTypeRequiredDescription
objectobjectyesThe object to inspect. null and undefined throw TypeError.
keystring | symbolyesThe property key. Non-symbol values are coerced to strings, so 1 and "1" are the same key.

Return value

boolean — True if the key is an OWN property of the object — inherited properties do not count. Works even when the object has a null prototype or a shadowed hasOwnProperty.

Common patterns

Check before reading
Distinguishes "absent" from "present but falsy".
if (Object.hasOwn(config, "retries")) use(config.retries);
Safe iteration over untrusted data
Works on parsed JSON with any keys at all.
for (const k in data) {
  if (!Object.hasOwn(data, k)) continue;
}
Include inherited properties deliberately
The in operator walks the chain.
if ("toString" in obj) { }

Examples

1. Own property
Object.hasOwn({a: 1}, "a")
Returns
true
2. Absent
Object.hasOwn({a: 1}, "b")
Returns
false
3. Inherited is false
Object.hasOwn({}, "toString")
Returns
false
4. in says true
"toString" in {}
Returns
true
5. Null-prototype object
Object.hasOwn(Object.create(null), "a")
Returns
false
6. The method would throw
Object.create(null).hasOwnProperty("a")
Returns
TypeError: ...hasOwnProperty is not a function

Pitfalls

1. hasOwnProperty is not safe on arbitrary objects
This is why hasOwn was added. An object created with Object.create(null) has no prototype, so it has no hasOwnProperty method and calling one throws. Parsed JSON and dictionary objects are routinely built that way.
Throws
Object.create(null).hasOwnProperty("a")
TypeError: ...hasOwnProperty is not a function
Static form
Object.hasOwn(Object.create(null), "a")
false
2. A property named hasOwnProperty shadows the method
Untrusted data — a parsed JSON payload, a query string — can contain a key called hasOwnProperty, replacing the method with a value. The call then fails or, worse, returns whatever the attacker chose.
Shadowed
const o = JSON.parse('{"hasOwnProperty": 1}');
o.hasOwnProperty("x")
TypeError: o.hasOwnProperty is not a function
Cannot be shadowed
Object.hasOwn(o, "x")
false
3. It is not the in operator
in walks the whole prototype chain; hasOwn stops at the object itself. For a class instance, a method defined on the class is found by in and not by hasOwn — which is usually what you want, but not always.
Misses inherited
class A { m() {} }
Object.hasOwn(new A(), "m")
false
in finds it
"m" in new A()
true
4. ES2022 — check your runtime
Node 16.9+ and 2021-era browsers. The safe pre-2022 form is the borrowed call, which is verbose enough that most codebases wrapped it in a helper.
Missing
Object.hasOwn(o, k)
TypeError: Object.hasOwn is not a function
Borrow the method
Object.prototype.hasOwnProperty.call(o, k)
works everywhere

When to use

Use it
  • Testing whether a key exists, including when its value is falsy
  • Any object from untrusted input — parsed JSON, query strings
  • Objects created with Object.create(null)
  • Guarding a for...in loop
Reach for something else
  • You want inherited properties too → the in operator
  • You only care whether the value is set → a truthiness or != null check
  • You are listing every key → Object.keys
  • Targeting runtimes older than 2021 → the borrowed-call form

Notes

Complexity
O(1) — one own-property lookup, no chain walk
Return
A boolean; nothing is allocated
CPython impl
V8: Builtins-object-hasown
Memory
No allocation
Thread-safe
Single-threaded; the object is only read

FAQ

hasOwn for own properties, which is what data objects usually mean. in when inherited properties should count — checking for a method on a class instance, or feature-detecting on a DOM node.

Object.hasOwn(o, "toString");   // false
"toString" in o;                // true

History

ES5
Object.create(null) made prototype-less objects easy to build, and hasOwnProperty unsafe on them.
ES2022
Object.hasOwn added as the static, un-shadowable replacement.