`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.hasOwn
与 Object.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.hasOwn
与 Object.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,
})
}
除此之外我们在平时的开发过程中也会使用社区提供的工具库 has 和 lodash.has,它们都能很好地判断对象的属性。
浏览器支持情况
浏览器对 Object.hasOwn
的支持情况如下:
- Chrome 93+ and Chrome for Android 102+
- Firefox 92+ and Firefox for Android 102+
- Safari 15.4+
- Edge 93+