The following function is mentioned in Speaking Javascript: An In-Depth Guide for Programmers by Axel Rauschmayer:
function getDefiningObject(obj, propKey) {
obj = Object(obj); // make sure it’s an object
while (obj && !{}.hasOwnProperty.call(obj, propKey)) {
obj = Object.getPrototypeOf(obj);
// obj is null if we have reached the end
}
return obj;
}
Its purpose, as the author puts it, is "to [iterate] over the property chain of an object obj
[and return] the first object that has an own property with the key propKey
, or null
if there is no such object".
I understand the overall reasoning here, but what I don't understand is why {}.hasOwnProperty.call(obj, propKey)
is being done rather than just obj.hasOwnProperty(propKey)
. Any ideas?
If you want to execute
Object.prototype.hasOwnProperty
on an object, and you attempt to useobj.hasOwnProperty(prop)
you're making some assumptions:"hasOwnProperty"
. This is easy to fail if you create objects usingObject.create(null)
.obj.hasOwnProperty
. This is easy to fail if the object has a key that has been added named"hasOwnProperty"
. You might think this is a rare case, but it's not uncommon to parse things such as query strings into objects, and query strings are user-supplied.Using
Object.prototype.hasOwnProperty.call(obj, prop)
you're reasonably guaranteed to have the method you want called on the object that's being passed in as input.For utility purposes it's quite common to see something along the lines of:
Often, developers will use
call
on a built-in type to ensure that they are getting the correct native behavior of a method and not some overridden behavior.It is a protective measure that we really shouldn't have to use, but because Objects are so malleable in JavaScript, it guarantees we get the behavior we desire.
Imagine if someone (who, intentionally or accidentally) created an object like this:
And then, you came along (without having seen the implementation of the object) and wrote:
You'd get this:
So, instead we get code like this:
It forces the
hasOwnProperty
to be looked up on the prototype chain of the nativeObject
, while:relies on that property being available and correct on a particular instance of an object (
obj
).Other popular examples of this are with the Array type:
Because
obj.hasOwnProperty
would terribly fall if the object was defined like these:With
{}.hasOwnProperty
you get a reference to the desired function fromObject.prototype
, you don't need to worry about it being shadowed somewhere closer in the prototypical chain, or the object not inheriting fromObject.prototype
.This is a design problem, because
hasOwnProperty
should have been a static method, but now it's too late to fix it. Another solution is implementing HasOwnProperty manually: