【发布时间】:2017-03-13 03:48:01
【问题描述】:
在 JavaScript 中,in 运算符检查对象是否具有指定的属性。但是,它不仅检查对象自身的属性,还检查原型链。因此,在某些情况下,它的行为可能不完全符合预期。
假设由于某种原因我们有一个对象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,所以in操作符返回true,即使这个对象没有自己的toString属性。
这就是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...
为了解决这个问题,我们可以直接从Object.prototype引用该方法,而不是使用someObject.hasOwnProperty:
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
【问题讨论】:
-
在大多数情况下,如果一个函数接受具有某些属性的东西 - 它不应该是它的业务在原型链中定义属性的位置,而是它只是可用的。这样您就可以将数据形状与实现细节分开。
标签: javascript object prototype hasownproperty ecmascript-2016