阿里云主机折上折
  • 微信号
Current Site:Index > Object.hasOwn()

Object.hasOwn()

Author:Chuan Chen 阅读数:54649人阅读 分类: JavaScript

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:

  1. Throws a TypeError when the object is null or undefined
  2. Can be overridden by an object's own hasOwnProperty property
  3. 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

  1. Safely checking property existence:
function getUserProperty(user, prop) {
  return Object.hasOwn(user, prop) ? user[prop] : undefined
}
  1. 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
  1. 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属性

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.