Skip to main content

Difference between in operator and hasOwnProperty() method in JavaScript

The in operator checks if a property exists anywhere in an object's prototype chain, including inherited ones. hasOwnProperty() looks only at the object's own properties and skips the chain entirely.

Theory

TL;DR

  • in is like asking "does this house or any ancestor have a garage?" hasOwnProperty() asks "does this specific house have one?"
  • Main difference: in walks up the prototype chain, hasOwnProperty() stops at the object itself
  • Both work with non-enumerable own properties. Object.keys() is the one that filters by enumerability, not hasOwnProperty()
  • Use in for full existence checks or pre-access safety. Use hasOwnProperty() to exclude inherited properties

Quick example

javascript
const parent = { skill: 'coding' }; const child = Object.create(parent); child.name = 'Alice'; console.log('name' in child); // true (own property) console.log('skill' in child); // true (inherited from parent) console.log(child.hasOwnProperty('name')); // true console.log(child.hasOwnProperty('skill')); // false (lives on parent, not child)

in found both properties. hasOwnProperty() returned false for skill because it belongs to parent, not to child directly.

Key difference

in triggers the [[HasProperty]] internal method which walks the [[Prototype]] chain upward until it finds a match or hits null. hasOwnProperty() goes straight to the object's local property map and never looks up the chain. Both methods see non-enumerable own properties. The one that filters by enumerability is Object.keys(), not hasOwnProperty().

When to use

  • Checking before accessing a prop (safety guard before obj.prop): use in
  • Full feature detection, including browser APIs on prototypes: use in
  • Filtering direct keys inside a for...in loop: use hasOwnProperty()
  • Serializing only user-defined properties, not defaults inherited from a prototype: use hasOwnProperty()
  • Protecting against prototype pollution in library code: use hasOwnProperty()

Comparison table

CharacteristicinhasOwnProperty()
Searches prototype chainYesNo (own only)
Non-enumerable own propertiesReturns trueReturns true
Null-prototype objects (Object.create(null))Works fineThrows TypeError if called directly
PerformanceSlower (chain traversal)Faster (local lookup)
Typical use caseSafe access, feature detectionfor...in filtering, serialization

How JavaScript handles this

in calls the ECMAScript [[HasProperty]] internal method, which follows [[Prototype]] links until it finds the key or reaches null. hasOwnProperty() calls OrdinaryOwnPropertyKeys directly on the object's property map. That is why hasOwnProperty() runs roughly 2-3x faster in tight loops.

Common mistakes

Mistake: for...in without filtering own properties

javascript
function User() {} User.prototype.greet = function() {}; const user = new User(); user.name = 'Alice'; for (let key in user) { console.log(key); // 'name', then 'greet' (inherited!) }

for...in iterates all enumerable properties, including inherited ones. Fix it with hasOwnProperty():

javascript
for (let key in user) { if (user.hasOwnProperty(key)) { console.log(key); // only 'name' } }

Or just use Object.keys(user), which returns own enumerable keys directly.

Mistake: calling hasOwnProperty on a null-prototype object

javascript
const config = Object.create(null); // no prototype config.port = 3000; config.hasOwnProperty('port'); // TypeError: config.hasOwnProperty is not a function

Objects created with Object.create(null) have no prototype, so they do not inherit hasOwnProperty. Fix:

javascript
Object.prototype.hasOwnProperty.call(config, 'port'); // true // Or the cleaner modern option: Object.hasOwn(config, 'port'); // true (ES2022)

I ran into this in a Node.js config loader where null-prototype objects were used to prevent prototype pollution. Object.hasOwn fixed it cleanly.

Mistake: thinking hasOwnProperty skips non-enumerable properties

javascript
const obj = {}; Object.defineProperty(obj, 'hidden', { value: 99, enumerable: false }); console.log('hidden' in obj); // true console.log(obj.hasOwnProperty('hidden')); // true (not false!) console.log(Object.keys(obj)); // [] <- this one skips non-enumerable

hasOwnProperty() does not care about enumerability. It returns true for any own property. Object.keys() is the one that requires enumerable: true.

Real-world usage

  • React: for...in + hasOwnProperty in ReactElementValidator to check propTypes (React 18)
  • Express: req.hasOwnProperty('user') to guard against prototype leaks in middleware
  • Lodash: _.has(object, path) uses in-style logic for safe deep property access
  • Node.js: null-prototype objects in config parsers, paired with Object.hasOwn

Follow-up questions

Q: What happens when you use in on an Object.create(null) object?
A: It works for own properties but finds nothing inherited, since there is no prototype chain. 'toString' in Object.create(null) returns false.

Q: What is Object.hasOwn() and how does it differ from hasOwnProperty()?
A: Object.hasOwn(obj, key) was added in ES2022. It does the same thing but works correctly on null-prototype objects. Prefer it in new code.

Q: How to safely iterate only own keys?
A: Use Object.keys(obj) for own enumerable keys, or for...in with a hasOwnProperty() filter. Object.keys is the cleaner option.

Q: In a Proxy-trapped object, does in respect custom behavior?
A: Yes. in calls the Proxy's has trap, so you can intercept the check. hasOwnProperty() bypasses the trap and goes directly to the target object. This is defined in the ES2022 spec and matters in metaprogramming contexts.

Examples

Checking inherited vs own in a class hierarchy

javascript
function Animal(name) { this.name = name; } Animal.prototype.type = 'animal'; const dog = new Animal('Rex'); console.log('name' in dog); // true (own property) console.log('type' in dog); // true (inherited from Animal.prototype) console.log(dog.hasOwnProperty('name')); // true console.log(dog.hasOwnProperty('type')); // false

type lives on Animal.prototype, not on dog. in finds it anyway. hasOwnProperty() does not. This is the clearest way to see the difference.

Serializing only user-defined settings

javascript
const defaults = { theme: 'light', lang: 'en' }; const userConfig = Object.create(defaults); userConfig.lang = 'uk'; userConfig.fontSize = 16; // Save only what the user explicitly set const toSave = {}; for (let key in userConfig) { if (userConfig.hasOwnProperty(key)) { toSave[key] = userConfig[key]; } } console.log(toSave); // { lang: 'uk', fontSize: 16 } // 'theme' stays out because it is on defaults, not on userConfig

A pattern that comes up in configuration systems. Without the hasOwnProperty check, default values the user never touched would end up in the saved output.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?