繁体   English   中英

有什么情况我应该使用in运算符而不是hasOwnProperty()?

[英]Are there any cases when I should use the in operator instead of hasOwnProperty()?

在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方法 ,因此即使对象没有自己的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...

要解决这个问题,我们可以直接从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

你回答自己的问题。 in当你想在原型链搜索以及良好。

in是一个操作符,所以它不能被劫持。 您不必依赖于没有更改脚本或阴影的ObjectObject.prototypeObject.prototype.hasOwnPropertyObject.prototype.hasOwnProperty.call

这是一种了解对象是否具有某些属性的快速方法。 我的意思是,如果obj.foo可以返回例如"bar"即使foo属性是继承的,也可以事先知道obj是否具有foo属性,无论是拥有还是继承。

当然,如果我们只有HasOwnProperty,我们可以(通常)继续调用[[GetPrototypeOf]]直到链的末尾,并检查每个对象。 但是,这将是乏味的代码,可能比本地慢in ES5之前,并没有可能。

而且,存在根本的区别。 in运算符使用[[HasProperty]]内部方法,而HasOwnProperty使用[[GetOwnProperty]]。 对于非普通对象,迭代[[GetOwnProperty]]和[[GetPrototypeOf]]可能会产生与[[HasProperty]]不同的结果。

所以是的:当你想调用一个对象的内部[[HasProperty]]方法时, in运算符很有用。 事实上,除了Reflect.has ,它是唯一正确的方法。

 var p = new Proxy({}, {has: function() { console.log('Hooray!'); return true; }}); p.hasOwnProperty('foo'); // :( 'foo' in p; // Hooray! :) 

用于加载polyfill的功能检测,使用现代DOM API的测试条件等。

使用in运算符非常适合评估是否应该精确加载/执行JavaScript polyfill,因为它会检查原型链。

例如:

// this works wonderfully
if (!('addEventListener' in window)) {
  // polyfill addEventListener
}

相比:

// this doesn't work at all
if (!window.hasOwnProperty('addEventListener')) {
  // polyfill addEventListener
}

因此,Polyfill.io服务将其用于其特征检测测试的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM