For a long time, the Object.prototype.hasOwnProperty()
method was the standard way to check if an object had a property as its own property (as distinct from an inherited property) in JavaScript. However, the newer Object.hasOwn()
method works in situations where the older method doesn’t.
The Object.prototype.hasOwnProperty()
method
All objects (except those will a null
prototype) inherit the Object.prototype.hasOwnProperty()
method from their prototype chain. You can invoke this method on any such Object
instance.
let hedgehog = {
name: "sonic",
color: "blue",
};
hedgehog.hasOwnProperty("color"); // true
hedgehog.hasOwnProperty("toString"); // false
The object referenced by the hedgehog
variable has two of its own properties: .name
and .color
. When we invoke hedgehog.hasOwnProperty("color")
, the return value is true
, because .color
is one of the object’s own properties.
When we invoke hedgehog.hasOwnProperty("toString")
, the return value is false
. Although the object inherits the Object.prototype.toString()
method from its prototype (Object.prototype
), it isn’t one of the object’s own properties.
The Object.hasOwn()
method
The Object.hasOwn()
method works almost identically to the Object.prototype.hasOwnProperty()
method. The only difference is that you invoke it directly on Object
, not on an Object
instance. In other words, it’s a static method instead of an instance method. You pass in the Object
instance as the first argument and the property name as the second argument.
let hedgehog = {
name: "sonic",
color: "blue",
};
Object.hasOwn(hedgehog, "color"); // true
Object.hasOwn(hedgehog, "toString"); // false
The Object.hasOwn()
method works in two situations where the Object.prototype.hasOwnProperty()
method doesn’t:
- Objects with a
null
prototype. - Objects that override (shadow) the
Object.prototype.hasOwnProperty()
method.
Objects with a null
prototype
When you create an object literal with the object initializer syntax, the object referenced by the Object.prototype
property becomes the prototype of the new object (unless you specify a different object via the __proto__
key). We can use the Object.getPrototypeOf()
method to confirm this.
let hedgehog = {
name: "sonic",
color: "blue",
};
Object.getPrototypeOf(hedgehog) === Object.prototype; // true
The prototype of the object referenced by the Object.prototype
property is null
, marking the end of the prototype chain. We can still invoke the Object.prototype.hasOwnProperty()
on this object because it’s one of the object’s own properties.
Object.getPrototypeOf(Object.prototype) === null; // true
Object.prototype.hasOwnProperty("toString"); // true
However, it’s also possible to create an object with a null
prototype. You can either add a __proto__
key using the object initializer syntax or invoke the Object.create()
method.
let x = { __proto__: null };
Object.getPrototypeOf(x) === null; // true
let y = Object.create(null);
Object.getPrototypeOf(y) === null; // true
Because the objects referenced by the x
and y
variables don’t inherit from Object.prototype
, they don’t have access to the Object.prototype.hasOwnProperty()
method. If you try to invoke it, the JavaScript interpreter will throw a TypeError
.
x.hasOwnProperty("prop"); // TypeError: x.hasOwnProperty is not a function
y.hasOwnProperty("prop"); // TypeError: y.hasOwnProperty is not a function
Note that this is also a problem for objects that inherit from an object with a null
prototype. Even though these objects’ prototype isn’t null
, Object.prototype
still doesn’t appear anywhere in their prototype chain, so they still don’t inherit from it.
let x = { __proto__: null };
let y = Object.create(x);
Object.getPrototypeOf(y) === x; // true
y.hasOwnProperty("prop"); // TypeError: y.hasOwnProperty is not a function
The Object.hasOwn()
method solves this problem. Because the method is invoked directly on Object
, and not on the Object
instance (which doesn’t inherit from Object.prototype
), it works as expected. No TypeError
is thrown.
let x = { __proto__: null };
Object.hasOwn(x, "prop"); // false
let y = Object.create(null);
Object.hasOwn(y, "prop"); // false
Objects that override (shadow) the Object.prototype.hasOwnProperty()
method
When an object overrides a property that it inherits from its prototype chain, it is said to shadow that property. The inherited property still exists in the prototype chain, but because of the way property lookup occurs, the JavaScript interpreter won’t search for it further up the chain once it’s been found.
let hedgehog = {
name: "shadow",
color: "black",
hasOwnProperty() {},
};
hedgehog.hasOwnProperty("color"); // undefined
The object referenced by the hedgehog
variable has its own implementation of the .hasOwnProperty()
method. Because the function body is empty, the method’s implicit return value is undefined
. You might unwittingly use this method in your code, unaware that it shadows the Object.prototype.hasOwnProperty()
method. Regardless of the function body, the point here is that you can’t rely on the Object.prototype.hasOwnProperty()
method if an object has shadowed it. The Object.hasOwn()
method solves this problem.
let hedgehog = {
name: "shadow",
color: "black",
hasOwnProperty() {},
};
Object.hasOwn(hedgehog, "color"); // true
The Function.prototype.call()
method
It’s worth noting that you can use the Function.prototype.call()
method to solve these problems too, but the Object.hasOwn()
method is clearly more ergonomic.
let x = { __proto__: null };
Object.prototype.hasOwnProperty.call(x, "prop"); // false
let hedgehog = {
name: "shadow",
color: "black",
hasOwnProperty() {},
};
Object.prototype.hasOwnProperty.call(hedgehog, "color"); // true
Summary
The Object.hasOwn()
method is intended as a replacement for the Object.prototype.hasOwnProperty()
method. The former works in two situations where the latter doesn’t: on objects with a null
prototype and on objects that shadow the Object.prototype.hasOwnProperty()
method. However, the Object.hasOwn()
method has only been around since Chrome 93 / Firefox 92 / Safari 15.4, while the Object.prototype.hasOwnProperty()
method dates all the way back to IE 6. Keep this in mind if browser support is an issue.