Object.hasOwn vs. hasOwnProperty: Safe Property Checks Without Pitfalls
AI generated
JS
() =>
JavaScript · ES2022 · Objects · Security
Object.hasOwn vs. hasOwnProperty
Safe Property Checks Without Pitfalls

obj.hasOwnProperty(key) looks harmless, but it breaks with null prototype objects and with overridden prototype methods. Object.hasOwn(obj, key) is the static, robust alternative that avoids exactly these pitfalls and should be the default choice for property checks in modern code.

13 min read Object.hasOwn · Prototype Chains · Object.create(null) · Proxy Node 16.9+ · Chrome 93+ · ES2022

1. Why a New Method for Something So Simple?

At first glance, Object.hasOwn looks like an unnecessary addition: obj.hasOwnProperty(key) has existed since the early days of JavaScript and seems to do exactly the same thing. But the difference lies precisely in the word "seems". hasOwnProperty is a method inherited from the prototype, and this very inheritance is the source of several subtle bugs that keep showing up in real code.

Object.hasOwn solves the problem by implementing the check as a static function that works independently of the object being checked. Instead of calling a method on the object, which could theoretically be tampered with or not exist at all, you pass the object as an argument to a function that lives on Object itself. This seemingly small shift in responsibility is the real core of why Object.hasOwn is the safer choice in modern JavaScript code.

2. Object.hasOwn: Syntax and Return Value

The syntax of Object.hasOwn is deliberately simple: Object.hasOwn(obj, prop) takes the object to check as the first argument and the property name as the second, and returns a boolean that indicates precisely whether the object has its own, direct property with that name. Inherited properties from the prototype are deliberately ignored, exactly like with the classic hasOwnProperty method.

The decisive advantage only becomes clear in the calling syntax: Object.hasOwn is never called on the object being checked, but always on Object. That means it is completely irrelevant what prototype the passed object has, whether it overrides its own methods, or whether it even has a working prototype chain at all. This decoupling is the actual technical advance over the old method.


const config = { debug: true, retries: 3 };

// Object.hasOwn: static call, independent of the object's prototype
console.log(Object.hasOwn(config, "debug"));   // true
console.log(Object.hasOwn(config, "toString")); // false — inherited, not own

// Old approach: method call on the object itself
console.log(config.hasOwnProperty("debug"));    // true, works fine here

3. The Null Prototype Problem: When hasOwnProperty Disappears

The most obvious failure case for hasOwnProperty occurs with objects created via Object.create(null). Such objects deliberately have no prototype, which is often desired in security relevant code to rule out prototype pollution from the outset. The problem: without a prototype there is also no inherited hasOwnProperty method, and calling obj.hasOwnProperty(key) throws a TypeError exception, because the method simply does not exist.

Object.hasOwn has no problem at all with this case, because the check is never called on the object itself. A null prototype object can be checked with Object.hasOwn just as safely as an ordinary object literal. Anyone who codes defensively and frequently uses Object.create(null) for configuration objects or lookup tables to avoid collisions with prototype properties benefits here directly, with no extra effort.


// Object.create(null) has no prototype at all
const dictionary = Object.create(null);
dictionary.hello = "world";

// This throws: TypeError, hasOwnProperty does not exist on this object
try {
  dictionary.hasOwnProperty("hello");
} catch (err) {
  console.error(err.message); // dictionary.hasOwnProperty is not a function
}

// Object.hasOwn works regardless of the object's prototype chain
console.log(Object.hasOwn(dictionary, "hello")); // true
console.log(Object.hasOwn(dictionary, "world")); // false

4. Overridden hasOwnProperty Methods as an Attack Surface

A second, more subtle failure case arises when an object itself defines a property called hasOwnProperty that is not the inherited method. This happens more often than one might think, for instance with objects that are dynamically assembled from untrusted data sources such as form input or JSON payloads. If a key named hasOwnProperty is present in that data, it overrides the inherited method, and the next call to obj.hasOwnProperty(key) suddenly no longer invokes the expected check, but the overridden value instead.

Object.hasOwn is completely immune to this kind of manipulation, because the check is never called on the potentially compromised object. In security critical code that works with user input or external APIs, this is a real hardening feature, not a theoretical detail. Anyone checking objects from untrusted sources should consistently use Object.hasOwn instead of the method on the object.

5. Object.hasOwn with Proxy Objects

Proxy objects add another layer of complexity. A proxy can implement the has trap and the getOwnPropertyDescriptor trap to fully customize the behavior of property checks. Object.hasOwn respects these traps correctly, because internally it relies on [[GetOwnProperty]], the same internal mechanism that Object.getOwnPropertyDescriptor also uses. A proxy that wants to selectively hide or simulate certain properties therefore works with Object.hasOwn exactly as expected.

This is relevant for frameworks and libraries that implement reactive objects via proxies, such as state management in modern frontend architectures. If such a library checks internally with Object.hasOwn instead of relying on the object method, the behavior stays correct even when consumers wrap the reactive objects in their own proxy wrappers. This consistency was not guaranteed with the old method.


const hidden = new Proxy({ secret: 42, visible: 1 }, {
  getOwnPropertyDescriptor(target, prop) {
    if (prop === "secret") return undefined; // hide this property
    return Object.getOwnPropertyDescriptor(target, prop);
  }
});

console.log(Object.hasOwn(hidden, "secret"));  // false — trap respected
console.log(Object.hasOwn(hidden, "visible")); // true

6. Practical Case: Safe Object Iteration with for...in

The classic combination of for...in with hasOwnProperty filtering is a decades old pattern used to consider only own properties when iterating over an object and to ignore inherited prototype properties. In code that works with generic objects of unknown origin, this filtering should always use Object.hasOwn instead of the method on the object, to be protected against the pitfalls described above.

In newer code, Object.entries or Object.keys is often the better choice, because both inherently return only own, enumerable properties and require no filtering. But when encountering for...in loops in existing code, for example while working through older codebases, replacing the filter condition with Object.hasOwn is a low risk, targeted improvement.


const merged = Object.assign(Object.create({ inherited: "from prototype" }), {
  own1: "a",
  own2: "b"
});

// Safe iteration: only own properties, robust against overridden methods
for (const key in merged) {
  if (Object.hasOwn(merged, key)) {
    console.log(key, merged[key]); // own1 a / own2 b — "inherited" is skipped
  }
}

7. Checking Objects Coming From JSON

Objects that come from JSON.parse always have the normal Object.prototype and work fine with either method in most cases. The exception arises as soon as the JSON itself contains keys such as hasOwnProperty, constructor or __proto__, for instance with user input that was serialized into a JSON object. In this case, the parsed value overrides the inherited method the same way described in the previous section.

Anyone processing configuration files, webhook payloads or form data as JSON should generally assume that arbitrary key names can occur. Object.hasOwn makes the property check independent of the content of the data in these cases and rules out an entire class of bugs that would otherwise only surface in production, exactly when the "wrong" key name shows up in the JSON.

8. Migrating Existing Code: When the Switch Pays Off

A blanket replacement of every hasOwnProperty use with Object.hasOwn is rarely necessary, but at certain points in the code the switch has clear value. It is particularly relevant for functions that accept generic objects from external sources, for utility functions in shared libraries, and for any code working with objects created via Object.create(null).

For internal code that only works with self controlled, simple object literals, the switch brings little practical benefit, though it does not hurt either. A good compromise is to set Object.hasOwn as the new standard for all newly written property checks, without rewriting existing, working code purely out of consistency. Linter rules such as eslint-plugin-es-x can automatically enforce the switch for newly written code.

9. Object.hasOwn Compared Directly

The following table contrasts the key differences between the classic method and the new static function and shows in which situations the difference actually becomes practically relevant.

Situation obj.hasOwnProperty(key) Object.hasOwn(obj, key) Outcome
Object.create(null) TypeError true / false Object.hasOwn always works
Own hasOwnProperty in the object Wrong result Correct result Object.hasOwn is immune
Proxy with custom traps Depends on trap setup Respects traps correctly Both possible, hasOwn more consistent
Ordinary object literal Works Works No practical difference
Readability in code Method call, familiar Static call, more explicit Matter of taste, slight edge to hasOwn

In practice this shows: for simple, self controlled objects the difference is cosmetic, while for objects of unknown origin Object.hasOwn becomes a real safeguard against runtime errors and manipulation.

Mironsoft

Robust JavaScript code and hardening against runtime errors

Code that stays stable even with untrusted data?

We review existing JavaScript code for fragile property access, replace outdated patterns with robust alternatives such as Object.hasOwn, and harden your applications against prototype pollution and manipulated objects.

Security Review

Checking object access and prototype chains for manipulation risks

Code Modernization

Replacing outdated property checks with modern ES2022 patterns

Lint Rules

Setting up automated ESLint rules for consistent property access

10. Summary

Object.hasOwn solves a problem many developers have underestimated for years: the inherited method hasOwnProperty can be missing due to null prototypes or overridden by an object's own properties, and both cases lead to runtime errors or incorrect check results. As a static function on Object, Object.hasOwn is immune to both pitfalls, because the check never takes place on the potentially compromised object itself.

For new code, Object.hasOwn is the clear recommendation, especially for functions that accept generic objects from external sources such as JSON payloads, form data or configuration files. With objects created via Object.create(null) or proxy wrappers, switching is not just a matter of style but prevents concrete bugs that would otherwise only become visible in production.

Object.hasOwn — Key Points at a Glance

Core Principle

Static function Object.hasOwn(obj, key) instead of a method call on the object itself, independent of the prototype.

Null Prototype Objects

Works correctly with Object.create(null), while hasOwnProperty throws a TypeError there.

Manipulation Safety

Immune to own hasOwnProperty properties in the checked object, relevant for untrusted data sources.

Practical Recommendation

Set as the standard for new code, especially for generic objects and JSON payloads.

11. FAQ: Object.hasOwn vs. hasOwnProperty

1Main difference between both methods?
Object.hasOwn is static and takes the object as an argument, hasOwnProperty is called on the object itself and depends on its prototype.
2Why does hasOwnProperty fail with Object.create(null)?
Without a prototype the inherited method is completely absent, the call throws a TypeError exception.
3Can hasOwnProperty be overridden?
Yes, a key of that exact name in the object fully overrides the inherited method.
4Does it work with proxy objects?
Yes, Object.hasOwn respects correctly implemented proxy traps like getOwnPropertyDescriptor.
5Should I switch all code?
Not universally, but clearly recommended for generic objects from external sources.
6Is Object.hasOwn slower?
No, the performance difference is negligible, both use the same internal mechanism.
7Which versions support it?
Node.js 16.9, Chrome 93, Firefox 92, Safari 15.4. Polyfills exist for older environments.
8Safest way to check JSON data?
Always use Object.hasOwn, because JSON keys can carry arbitrary names, including hasOwnProperty itself.
9Does it replace the in operator?
No, in also checks inherited properties, Object.hasOwn only own direct properties.
10Usable in for...in loops?
Yes, a common and more robust use case than classic hasOwnProperty filtering.