Object.prototype.hasOwnProperty()
In this blog post, we examine the ECMAScript proposal “Accessible Object.prototype.hasOwnProperty()
” (by Jamie Kyle and Tierney Cyren). It proposes a new, simpler way of checking if an object has an own (non-inherited) property.
In this section, we look at existing ways of checking if an object has an own property. Each of them has downsides, which is why Object.hasOwn()
is needed.
in
operator isn’t always what we want The in
operator checks if an object has a property with a given name:
> 'name' in {name: 'Jane'}
true
> 'name' in {}
false
However, if we treat objects as dictionaries, then we want to ignore inherited properties (and in
considers them). For example, interpreted as a dictionary, the following object should be empty, but in
says that it has the property 'toString'
:
> 'toString' in {}
true
That’s because {}
inherits method .toString()
from Object.prototype
:
> Object.getPrototypeOf({}) === Object.prototype
true
.hasOwnProperty()
isn’t safe All objects created via object literals inherit the method .hasOwnProperty()
from Object.prototype
. That method seems to do what we want:
> {name: 'Jane'}.hasOwnProperty('name')
true
> {}.hasOwnProperty('name')
false
> {}.hasOwnProperty('toString')
false
However, .hasOwnProperty()
fails in two cases.
First, we can create objects that don’t inherit from Object.prototype
and don’t have that method:
> Object.create(null).hasOwnProperty('name')
TypeError: Object.create(...).hasOwnProperty is not a function
Second, if an object has an own property with the name 'hasOwnProperty'
, then that property overrides Object.prototype.hasOwnProperty
and we can’t access it:
> {hasOwnProperty: 'yes'}.hasOwnProperty('name')
TypeError: {(intermediate value)}.hasOwnProperty is not a function
Object.prototype.hasOwnProperty()
directly To fix the issues we encountered in the previous section, we need to access Object.prototype.hasOwnProperty()
directly:
function hasProp(obj, propName) {
return Object.prototype.hasOwnProperty.call(obj, propName);
}
assert.equal(
hasProp(Object.create(null), 'name'), false);
assert.equal(
hasProp({hasOwnProperty: 'yes'}, 'name'), false);
hasProp()
works exactly like Object.hasOwn()
.
Object.hasOwn()
The new proposal works exactly the way we want:
> Object.hasOwn({name: 'Jane'}, 'name')
true
> Object.hasOwn({}, 'name')
false
> Object.hasOwn({}, 'toString')
false
> Object.hasOwn(Object.create(null), 'name')
false
> Object.hasOwn({hasOwnProperty: 'yes'}, 'name')
false
> Object.hasOwn({hasOwn: 'yes'}, 'name')
false
In general, objects are not good dictionaries: There are several pitfalls we have to contend with.
Instead, Maps are great dictionaries and have no pitfalls.
Object.hasOwn()
Object.hasOwnProperty()
be a better name? Alas, that name isn’t available anymore:
> 'hasOwnProperty' in Object
true
Why? Object
is a function, which is an object:
> const proto = Object.getPrototypeOf.bind(Object);
> proto(Object) === Function.prototype
true
> proto(proto(Object)) === Object.prototype
true
Object.hasOwn()
and Reflect.has()
? Reflect.has()
works like the in
operator and considers inherited properties:
> Reflect.has({ownProp: 123}, 'ownProp')
true
> Reflect.has({ownProp: 123}, 'toString')
true
Object.hasOwn()
ignores inherited properties:
> Object.hasOwn({ownProp: 123}, 'ownProp')
true
> Object.hasOwn({ownProp: 123}, 'toString')
false
.hasOwn()
added to Reflect
? Reflect
only contains ECMAScript Proxy traps. Therefore, it is not a suitable location for a utility method such as .hasOwn()
.
Object.hasOwn()
Object.hasOwn()
.object.hasown
by Jordan Harband is a polyfill.lodash.has()
to Object.hasOwn()
, you can use Jamie Kyle’s codemod.Material in the book “JavaScript for impatient programmers”: