Object.hasOwn()
Overview of the Object.hasOwn() Method
ECMAScript 13 introduced the Object.hasOwn()
method as a safer and more intuitive alternative for checking whether an object has a specific property. This method addresses some historical issues with Object.prototype.hasOwnProperty()
, particularly offering more reliable behavior when dealing with null
or undefined
objects.
Why Object.hasOwn() is Needed
The traditional hasOwnProperty()
method has several notable drawbacks:
- Throws a TypeError when the object is
null
orundefined
- Can be overridden by an object's own
hasOwnProperty
property - Requires additional protective code to avoid runtime errors
const obj = { hasOwnProperty: 'I am not a function' }
// Traditional approach fails
try {
console.log(obj.hasOwnProperty('prop')) // TypeError: obj.hasOwnProperty is not a function
} catch (e) {
console.error(e)
}
// Safe usage requires this pattern
console.log(Object.prototype.hasOwnProperty.call(obj, 'prop')) // false
Basic Syntax and Usage
The Object.hasOwn()
method accepts two parameters:
static hasOwn(object: object, property: PropertyKey): boolean
Simple example:
const user = {
name: 'Alice',
age: 30
}
console.log(Object.hasOwn(user, 'name')) // true
console.log(Object.hasOwn(user, 'toString')) // false
console.log(Object.hasOwn(user, 'nonExistent')) // false
Comparison with hasOwnProperty
Both methods are functionally similar, but Object.hasOwn()
is safer:
const obj = Object.create(null) // Doesn't inherit from Object.prototype
// Traditional approach fails
console.log(obj.hasOwnProperty) // undefined
try {
console.log(obj.hasOwnProperty('prop'))
} catch (e) {
console.error(e) // TypeError
}
// New method works correctly
console.log(Object.hasOwn(obj, 'prop')) // false
Handling Edge Cases
Object.hasOwn()
has well-defined behavior for special values:
console.log(Object.hasOwn(null, 'prop')) // false
console.log(Object.hasOwn(undefined, 'prop')) // false
console.log(Object.hasOwn(42, 'prop')) // false
const sym = Symbol('key')
const objWithSymbol = { [sym]: 'value' }
console.log(Object.hasOwn(objWithSymbol, sym)) // true
Practical Use Cases
- Safely checking property existence:
function getUserProperty(user, prop) {
return Object.hasOwn(user, prop) ? user[prop] : undefined
}
- Iterating over an object's own properties:
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
[Symbol('internal')]: true
}
for (const key in config) {
if (Object.hasOwn(config, key)) {
console.log(`Config ${key}: ${config[key]}`)
}
}
// Output:
// Config apiUrl: https://api.example.com
// Config timeout: 5000
- Combining with Proxy:
const target = { _secret: 123, public: 'data' }
const proxy = new Proxy(target, {
has(target, prop) {
if (prop.startsWith('_')) return false
return Object.hasOwn(target, prop)
}
})
console.log(Object.hasOwn(proxy, '_secret')) // true
console.log('_secret' in proxy) // false
Performance Considerations
Object.hasOwn()
typically has a slight performance advantage over Object.prototype.hasOwnProperty.call()
because it's a direct built-in method call that doesn't require prototype chain lookup. This difference is negligible in most applications.
// Performance test example
const obj = { /* large number of properties */ }
console.time('hasOwn')
for (let i = 0; i < 1e6; i++) {
Object.hasOwn(obj, 'test')
}
console.timeEnd('hasOwn')
console.time('hasOwnProperty')
for (let i = 0; i < 1e6; i++) {
Object.prototype.hasOwnProperty.call(obj, 'test')
}
console.timeEnd('hasOwnProperty')
Browser Compatibility and Polyfill
As of the knowledge cutoff date, all major modern browsers support Object.hasOwn()
. For older environments, you can use this polyfill:
if (!Object.hasOwn) {
Object.defineProperty(Object, 'hasOwn', {
value: function(object, property) {
if (object == null) {
throw new TypeError('Cannot convert undefined or null to object')
}
return Object.prototype.hasOwnProperty.call(
Object(object),
property
)
},
configurable: true,
enumerable: false,
writable: true
})
}
Comparison with Other Property Checking Methods
JavaScript provides multiple ways to check properties, each with its own use cases:
const obj = { prop: 'value' }
Object.defineProperty(obj, 'nonEnum', {
value: true,
enumerable: false
})
console.log(Object.hasOwn(obj, 'prop')) // true
console.log(Object.hasOwn(obj, 'nonEnum')) // true
console.log(Object.hasOwn(obj, 'toString')) // false
console.log('prop' in obj) // true
console.log('nonEnum' in obj) // true
console.log('toString' in obj) // true
console.log(obj.prop !== undefined) // true
console.log(obj.nonEnum !== undefined) // true
console.log(obj.toString !== undefined) // true (inherited property)
TypeScript Integration
In TypeScript, Object.hasOwn()
can improve type inference:
interface User {
name?: string
age?: number
}
function getUserName(user: User): string {
// Previously required type assertion
// return user.hasOwnProperty('name') ? user.name! : 'Unknown'
// Now more concise
return Object.hasOwn(user, 'name') ? user.name : 'Unknown'
}
Working with Object.keys()
Object.hasOwn()
complements Object.keys()
, which only returns enumerable properties:
const obj = {}
Object.defineProperties(obj, {
enumProp: { value: 1, enumerable: true },
nonEnumProp: { value: 2, enumerable: false }
})
console.log(Object.keys(obj)) // ['enumProp']
console.log(Object.hasOwn(obj, 'enumProp')) // true
console.log(Object.hasOwn(obj, 'nonEnumProp')) // true
Usage in Classes
Object.hasOwn()
correctly identifies class instance's own properties:
class Person {
name = 'Default'
constructor(name) {
this.name = name
}
sayHello() {
console.log(`Hello, ${this.name}`)
}
}
const alice = new Person('Alice')
console.log(Object.hasOwn(alice, 'name')) // true
console.log(Object.hasOwn(alice, 'sayHello')) // false
Behavior with Arrays
For arrays, Object.hasOwn()
correctly identifies numeric index properties:
const arr = ['a', 'b', 'c']
arr.customProp = 'value'
console.log(Object.hasOwn(arr, '0')) // true
console.log(Object.hasOwn(arr, 'length')) // true
console.log(Object.hasOwn(arr, 'customProp')) // true
console.log(Object.hasOwn(arr, 'map')) // false (inherited from Array.prototype)
Relationship with JSON Serialization
Object.hasOwn()
checks properties that would be ignored by JSON.stringify():
const obj = {
data: 'normal',
[Symbol('id')]: 123,
method() {}
}
console.log(Object.hasOwn(obj, 'data')) // true
console.log(Object.hasOwn(obj, Symbol('id'))) // true
console.log(Object.hasOwn(obj, 'method')) // true
console.log(JSON.stringify(obj)) // {"data":"normal"}
Application in Deep Object Checking
While Object.hasOwn()
only checks direct properties, it can be combined to implement deep checking:
function deepHasOwn(obj, ...props) {
return props.reduce(
(current, prop) =>
current !== null && typeof current === 'object' && Object.hasOwn(current, prop)
? current[prop]
: undefined,
obj
) !== undefined
}
const nested = { a: { b: { c: 1 } } }
console.log(deepHasOwn(nested, 'a', 'b', 'c')) // true
console.log(deepHasOwn(nested, 'a', 'x')) // false
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:at()方法
下一篇:Error Cause属性