Accessible Object.prototype.hasOwnProperty()
Proposal for an Object.hasOwn()
method to make Object.prototype.hasOwnProperty()
more accessible.
๐ Now Gathering Community Feedback
Please see the Implementations section for polyfills and a codemod to start using Object.hasOwn()
in your code today.
If you are using Object.hasOwn()
please provide feedback in issue #18 (positive and/or negative feedback is encouraged).
Status
This proposal is currently at Stage 4
Authors:
- @jamiebuilds (Jamie Kyle, Rome)
- Champion: @bnb (Tierney Cyren, Microsoft)
Slides:
- For stage 1 on 2021/04 (Reached Stage 2)
- For stage 3 on 2021/05 (Reached Stage 3)
- Stage 3 update on 2021/07
- For stage 4 on 2021/08 (Reached Stage 4)
Motivation
Today, it is very common (especially in library code) to write code like:
let hasOwnProperty = Object.prototype.hasOwnProperty
if (hasOwnProperty.call(object, "foo")) {
console.log("has property foo")
}
This proposal simplifies that code to:
if (Object.hasOwn(object, "foo")) {
console.log("has property foo")
}
There are a number of existing libraries which make this more convenient:
This is a common practices because methods on Object.prototype
can sometimes be unavailable or redefined.
Object.create(null)
Object.create(null)
will create an object that does not inherit from Object.prototype
, making those methods inaccessible.
Object.create(null).hasOwnProperty("foo")
// Uncaught TypeError: Object.create(...).hasOwnProperty is not a function
Redefining hasOwnProperty
If you do not directly own every property defined of an object, you can't be 100% certain that calling .hasOwnProperty()
is calling the built-in method:
let object = {
hasOwnProperty() {
throw new Error("gotcha!")
}
}
object.hasOwnProperty("foo")
// Uncaught Error: gotcha!
ESLint no-prototype-builtins
ESLint has a built-in rule for banning use of prototype builtins like hasOwnProperty
.
From the ESLint documentation for
no-prototype-builtins
:
Examples of incorrect code for this rule:
/*eslint no-prototype-builtins: "error"*/ var hasBarProperty = foo.hasOwnProperty("bar"); ...
Examples of correct code for this rule:
/*eslint no-prototype-builtins: "error"*/ var hasBarProperty = Object.prototype.hasOwnProperty.call(foo, "bar"); ...
MDN hasOwnProperty()
advice
The MDN documentation for Object.prototype.hasOwnProperty
includes advice not to use it off of the prototype chain directly:
JavaScript does not protect the property name hasOwnProperty; thus, if the possibility exists that an object might have a property with this name, it is necessary to use an external hasOwnProperty to get correct results [...]
Proposal
This proposal adds a Object.hasOwn(object, property)
method with the same behavior as calling hasOwnProperty.call(object, property)
let object = { foo: false }
Object.hasOwn(object, "foo") // true
let object2 = Object.create({ foo: true })
Object.hasOwn(object2, "foo") // false
let object3 = Object.create(null)
Object.hasOwn(object3, "foo") // false
Implementations
Native implementations of Object.hasOwn
in JavaScript engines are available in:
- Browsers:
- V8 (shipped)
- SpiderMonkey (feature-flagged)
- JavaScriptCore (in-progress)
- Others:
Polyfills of Object.hasOwn()
are available in:
A codemod to migrate to Object.hasOwn()
from similar libraries is available:
There's also an eslint rule for enforcing usage of hasOwn
instead of hasOwnProperty
:
Q&A
Why not Object.hasOwnProperty(object, property)
?
Object.hasOwnProperty(property)
already exists today because Object
itself inherits from Object.prototype
so defining a new method with a different signature would be a breaking change.
Why the name hasOwn
?
See Issue #3
Why not use Map
for dictionaries instead of objects?
Excerpt from https://v8.dev/features/object-fromentries#objects-vs.-maps
JavaScript also supports Maps, which are often a more suitable data structure than regular objects. So in code that you have full control over, you might be using maps instead of objects. However, as a developer, you do not always get to choose the representation. Sometimes the data youโre operating on comes from an external API or from some library function that gives you an object instead of a map.
Why not place this method on Reflect
?
The purpose of Reflect
is to contain, 1:1, a method for each Proxy
trap. There is already a method on Proxy
that traps hasOwnProperty
(getOwnPropertyDescriptor
) so it doesn't make sense to add an additional trap, therefore it doesn't make sense to place this method on Reflect
.