Reputation: 92521
In JavaScript the in
operator checks whether an object has the specified property. However, it doesn't check only object's own properties, but also the prototype chain. Therefore in some situations it may behave not exactly as expected.
Let's say that for some reason we have an object someArrayMethods
containing (obviously) some array methods as keys:
const someArrayMethods = {
indexOf: true,
map: true,
};
We can check if that object has a specific method as a key using the in
operator:
console.log('indexOf' in someArrayMethods); // true
console.log('every' in someArrayMethods); // false
What if we tried to check for toString
property?
console.log('toString' in someArrayMethods); // true
Surprise! It turns out that this object has a toString
method in the prototype chain, so the in
operator returns true
even though the object doesn't have its own toString
property.
And here's where hasOwnProperty()
comes to the rescue! It's almost the same as the in
operator, with one difference: it doesn't check the prototype chain. We can rewrite our previous example:
console.log(someArrayMethods.hasOwnProperty('toString')); // false
Now it works as expected. Unfortunately, hasOwnProperty()
also can fail in one case. What if we had an object with an own property hasOwnProperty
? See this example:
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...
To solve this problem, instead of using someObject.hasOwnProperty
, we can refer to that method directly from Object.prototype
:
const hasOwn = Object.prototype.hasOwnProperty;
console.log(hasOwn.call(someObject, 'theAnswer')); // true
This seems to be the most reasonable approach for checking if an object has some property. Despite this, are there any cases where the in
operator would be useful? I know that it can be used to check if an instance of some class has some method, but in this case isn't it better to simply check if that object is an instance of that class?
As a side note, another option is to use Object.keys()
with ECMAScript 2016 Array.prototype.includes()
:
console.log(Object.keys(someObject).includes('theAnswer')); // true
Upvotes: 3
Views: 991
Reputation: 1903
Feature detection for loading polyfills, testing conditions for using modern DOM APIs etc.
Using the in
operator is ideal for assessing whether you should load/execute a JavaScript polyfill precisely because it checks the prototype chain.
For instance:
// this works wonderfully
if (!('addEventListener' in window)) {
// polyfill addEventListener
}
compared to:
// this doesn't work at all
if (!window.hasOwnProperty('addEventListener')) {
// polyfill addEventListener
}
Hence why the Polyfill.io service uses it for its feature detection tests.
Upvotes: 3
Reputation: 288260
in
is an operator, so it can't be hijacked. You don't have to rely on that no script altered or shadowed Object
, Object.prototype
, Object.prototype.hasOwnProperty
, Object.prototype.hasOwnProperty.call
.
And it's a fast way to know if an object has some property. I mean, if obj.foo
can return e.g. "bar"
even if the foo
property is inherited, it makes sense to be able to know if obj
has that foo
property or not beforehand, either own or inherited.
Sure, if we only had HasOwnProperty, we could (usually) keep calling [[GetPrototypeOf]] until the end of the chain, and check each object. But that would be tedious to code, probably slower than a native in
, and not possible before ES5.
Moreover, there is a fundamental difference. The in
operator uses the [[HasProperty]] internal method, while HasOwnProperty uses [[GetOwnProperty]]. Iterating [[GetOwnProperty]] and [[GetPrototypeOf]] may produce a different result than [[HasProperty]] for non-ordinary objects.
So yes: the in
operator is useful when you want to call the internal [[HasProperty]] method of an object. In fact, apart from Reflect.has
, it is the only proper way to do that.
var p = new Proxy({}, {has: function() {
console.log('Hooray!');
return true;
}});
p.hasOwnProperty('foo'); // :(
'foo' in p; // Hooray! :)
Upvotes: 5
Reputation: 2161
You answer your own question.
in
is good when you want to search in prototype chain as well.
Upvotes: 4