•  阅读 3 分钟

`Object.hasOwn` 检查对象是否包含某一属性参数

在过去我们判断某个字符串变量是否是对象的自有属性时,通常使用 Object 对象原型链上的 hasOwnProperty 方法来判断:

const hasOwnProperty = Object.prototype.hasOwnProperty

if (hasOwnProperty.call(object, 'foo')) {
  // `object` 包含属性 `foo`.
}

既然 Object.prototype 包含 hasOwnProperty 方法,且可以判断属性参数,为什么继承 Object 属性的 object 不直接使用 object.hasOwnProperty 呢?答案是 JavaScript 普通对象的原型可以被覆盖,使用 Object.prototype.hasOwnProperty 可以确保安全正确。

const baz = {
  hasOwnProperty() {
    return false
  },
  ba: 'own property',
}

可以看到 baz 对象拥有重新定义的 hasOwnProperty 方法,该方法覆盖从 Object.prototype 继承的方法 hasOwnProperty,直接调用 baz.hasOwnProperty('ba') 只会返回 false

另外 Object.create(null) 会创建一个空对象,该空对象没有继承 Object.prototype 对象,所以会报如下错误:

Object.create(null).hasOwnProperty('foo')
// Uncaught TypeError: Object.create(...).hasOwnProperty is not a function

Object.hasOwn 提案

现在 ECMAScript 官方正式提出 Object.hasOwn 提案,快捷判断对象自有属性,提高代码可读性。

if (Object.hasOwn(object, 'foo')) {
  // `object` 包含属性 `foo`.
}

提案方法 Object.hasOwnObject.prototype.hasOwnProperty.call(object, property) 具有相同的行为:

const object = { foo: false }
Object.hasOwn(object, 'foo') // true

const object2 = Object.create({ foo: true })
Object.hasOwn(object2, 'foo') // false

const object3 = Object.create(null)
Object.hasOwn(object3, 'foo') // false

const object4 = { foo: undefined, baz: null }
Object.hasOwn(object4, 'foo') // true
Object.hasOwn(object4, 'baz') // true

Object.hasOwn(example, 'toString') // false
Object.hasOwn(example, 'hasOwnProperty') // false

in 操作符

有时候我们根据需要使用 in 操作符判断某参数是否是对象的属性:

const object = { foo: false }
if ('foo' in object) {
  // `foo` 是 `object` 的属性
}

in 操作符与 Object.hasOwn 的不同在于除了判断对象的自有属性外,还会检查原型链上是否包含这一属性:

const object = {}
'toString' in object // true
'hasOwnProperty' in object // true
Object.hasOwn('toString') // false

for ... in 循环

JavaScript 中可以使用 for in 循环遍历一个对象,由于 in 操作符会检查原型链。所以需要使用 Object.hasOwn 跳过继承属性:

const object = { foo: true, bar: true }
for (const name in object) {
  if (Object.hasOwn(object, name)) {
    // ...
  }
}

检查数组是否包含某一个索引

由于数组 Array 是一种特殊的对象,我们也可以使用 Object.hasOwn 判断数组的索引:

const friends = ['吴文俊', '李星', '小郭', '浩哥', '小白龙']
Object.hasOwn(friends, 2) // true - '小郭'
Object.hasOwn(friends, 5) // false

polyfill 支持

在不支持的浏览器中,我们需要使用一些回退方式。我们利用 Object.hasOwnObject.prototype.hasOwnProperty.call(object, property) 的相同行为实现支持方案:

if (!Object.hasOwn) {
  Object.defineProperty(Object, 'hasOwn', {
    value(object, property) {
      if (object == null) {
        throw new TypeError('Cannot convert undefined or null to object')
      }
      return Object.prototype.hasOwnProperty.call(new Object(object), property)
    },
    configurable: true,
    enumerable: false,
    writable: true,
  })
}

除此之外我们在平时的开发过程中也会使用社区提供的工具库 haslodash.has,它们都能很好地判断对象的属性。

浏览器支持情况

浏览器对 Object.hasOwn 的支持情况如下:

  • Chrome 93+ and Chrome for Android 102+
  • Firefox 92+ and Firefox for Android 102+
  • Safari 15.4+
  • Edge 93+
> cd ..