在JavaScript中,in
运算符检查对象是否具有指定的属性。但是,它不仅检查对象自己的属性,还检查原型链。因此,在某些情况下,它可能表现得不尽如人意。有什么情况下,我应该使用in运算符而不是hasOwnProperty()?
比方说,由于某种原因,我们有一个对象someArrayMethods
含(显然)一些阵列方法作为键:
const someArrayMethods = {
indexOf: true,
map: true,
};
我们可以检查该对象是否具有一个特定的方法,使用in
运营商的关键:
console.log('indexOf' in someArrayMethods); // true
console.log('every' in someArrayMethods); // false
如果我们试图检查toString
属性,该怎么办?
console.log('toString' in someArrayMethods); // true
惊喜!事实证明,该对象在原型链中有toString
method,所以即使该对象没有自己的toString
属性,in
运算符也会返回true
。
这里的hasOwnProperty()
来救援!它几乎与in
运算符相同,但有一点不同:它不检查原型链。我们可以重写前面的例子:
console.log(someArrayMethods.hasOwnProperty('toString')); // false
现在它按预期工作。不幸的是,hasOwnProperty()
也可能在一种情况下失败。如果我们有一个拥有自己的财产hasOwnProperty
?看到这个例子:
const someObject = {
hasOwnProperty() {
return false;
},
theAnswer: 42,
};
// Does `someObject` has own property `theAnswer`?
console.log(someObject.hasOwnProperty('theAnswer')); // false
// Well, it seems it doesn't...
为了解决这个问题,而不是使用someObject.hasOwnProperty
,大家可以参考该方法直接从Object.prototype
:
const hasOwn = Object.prototype.hasOwnProperty;
console.log(hasOwn.call(someObject, 'theAnswer')); // true
这似乎是最合理的方法来检查,如果一个对象有一些属性。尽管如此,是否有任何情况下in
运营商将有用?我知道它可以用来检查某个类的实例是否有某种方法,但是在这种情况下简单地检查该对象是否是该类的一个实例并不好?
作为一个侧面说明,另一种选择是使用Object.keys()
与ECMAScript的2016 Array.prototype.includes()
:
console.log(Object.keys(someObject).includes('theAnswer')); // true
在大多数情况下,如果一个函数接受一些东西属性 - 它不应该是它的业务,其中在原型链中的属性定义,但它只是提供。这样你就可以将数据形状与实现细节分开。 – zerkms