在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
属性。 / p>
这里是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
答案 0 :(得分:4)
你回答自己的问题。
当您想在原型链中搜索时,in
也很好。
答案 1 :(得分:4)
in
是一个运营商,因此无法被劫持。您不必依赖于没有更改或隐藏的脚本Object
,Object.prototype
,Object.prototype.hasOwnProperty
,Object.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! :)

答案 2 :(得分:2)
用于加载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
}
因此the Polyfill.io service将其用于特征检测测试。