本文首发于我的个人 Blog,永久地址:https://tie.pub/blog/object-has-own/,
欢迎大家订阅。
在过去我们判断某个字符串变量是否是对象的自有属性时,通常使用 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: function () {
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)
具有相同的行为:
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
let 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
操作符判断某参数是否是对象的属性:
let object = { foo: false };
if ('foo' in object) {
// `foo` 是 `object` 的属性
}
in
操作符与 Object.hasOwn
的不同在于除了判断对象的自有属性外,还会检查原型链上是否包含这一属性:
let object = {};
'toString' in object; // true
'hasOwnProperty' in object; // true
Object.hasOwn('toString'); //false
for ... in
循环
JavaScript 中可以使用 for in
循环遍历一个对象,由于 in
操作符会检查原型链。所以需要使用 Object.hasOwn
跳过继承属性:
let object = { foo: true, bar: true };
for (let name in object) {
if (Object.hasOwn(object, name)) {
// ...
}
}
检查数组是否包含某一个索引
由于数组 Array 是一种特殊的对象,我们也可以使用 Object.hasOwn
判断数组的索引:
let 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: 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,
});
}
除此之外我们在平时的开发过程中也会使用社区提供的工具库 has 和 lodash.has,它们都能很好地判断对象的属性。
浏览器支持情况
截至文章发布日 2021 年 11 月 9 日,浏览器对 Object.hasOwn
的支持情况如下:
- Chrome 93+
- Firefox 92+
- Safari 不支持
- Edge 93+
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。