Why use Object.prototype.hasOwnProperty.call(myObj, prop) instead of myObj.hasOwnProperty(prop)?
Asked Answered
H

6

142

If I understand correctly, each and every object in JavaScript inherits from the Object prototype, which means that each and every object in JavaScript has access to the hasOwnProperty function through its prototype chain.

While reading RequireJS' source code, I stumbled upon this function:

function hasProp(obj, prop) {
    return hasOwn.call(obj, prop);
}

hasOwn is a reference to Object.prototype.hasOwnProperty. Is there any practical difference to writing this function as

function hasProp(obj, prop) {
    return obj.hasOwnProperty(prop);
}

And since we are at it, why do we define this function at all? Is it just a question of shortcuts and local caching of property access for (slight) performance gains, or am I missing any cases where hasOwnProperty might be used on objects which don't have this method?

Hadst answered 18/8, 2012 at 10:9 Comment(1)
Closely related: Why were ES5 Object methods not added to Object.prototype?Galumph
C
144

Is there any practical difference [between my examples]?

The user may have a JavaScript object created with Object.create(null), which will have a null [[Prototype]] chain, and therefore won't have hasOwnProperty() available on it. Using your second form would fail to work for this reason.

It's also a safer reference to Object.prototype.hasOwnProperty() (and also shorter).

You can imagine someone may have done...

var someObject = {
    hasOwnProperty: function(lol) {
        return true;
    }
};

Which would make a hasProp(someObject) fail had it been implemented like your second example (it would find that method directly on the object and invoke that, instead of being delegated to Object.prototype.hasOwnProperty).

But it's less likely someone will have overridden the Object.prototype.hasOwnProperty reference.

And since we are at it, why do we define this function at all?

See above.

Is it just a question of shortcuts and local caching of property access for (slight) performance gains...

It may make it quicker in theory, as the [[Prototype]] chain doesn't have to be followed, but I suspect this to be negligible and not the reason the implementation is why it is.

... or am I missing any cases where hasOwnProperty might be used on objects which don't have this method?

hasOwnProperty() exists on Object.prototype, but can be overridden. Every native JavaScript object (but host objects are not guaranteed to follow this, see RobG's in-depth explanation) has Object.prototype as its last object on the chain before null (except of course for the object returned by Object.create(null)).

Czarra answered 18/8, 2012 at 10:11 Comment(3)
Your logic is probably correct, but I think you're being kind. If the authors of require.js think hasOwnProperty might have been overridden (which is extremely unlikely), then they should be calling all built-in methods that way (perhaps they do).Selfwill
@Periback Really? I was pretty sure it did support it.Czarra
ES6 shortcut if used often. const hasProp = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop)Unwary
S
18

If I understand correctly, each and every object in JavaScript inherits from the Object prototype

It might seem like splitting hairs, but there is a difference between JavaScript (the generic term for ECMAScript implementations) and ECMAScript (the language used for JavaScript implementations). It is ECMAScript that defines an inheritance scheme, not JavaScript, so only native ECMAScript objects need to implement that inheritance scheme.

A running JavaScript program consists of at least the built–in ECMAScript objects (Object, Function, Number, etc.) and probably some native objects (e.g. functions). It may also have some host objects (such as DOM objects in a browser, or other objects in other host environments).

While built–in and native objects must implement the inheritance scheme defined in ECMA-262, host objects do not. Therefore, not all objects in a JavaScript environment must inherit from Object.prototype. For example, host objects in Internet Explorer implemented as ActiveX objects will throw errors if treated as native objects (hence why try..catch is used to initialise Microsoft XMLHttpRequest objects). Some DOM objects (like NodeLists in Internet Explorer in quirks mode) if passed to Array methods will throw errors, DOM objects in Internet Explorer 8 and lower do not have an ECMAScript–like inheritance scheme, and so on.

Therefore it should not be assumed that all objects in a JavaScript environment inherit from Object.prototype.

which means that each and every object in JavaScript has access to the hasOwnProperty function through its prototype chain

Which is not true for certain host objects in Internet Explorer in quirks mode (and Internet Explorer 8 and lower always) at least.

Given the above, it's worth pondering why an object might have its own hasOwnProperty method and the advisability of calling some other hasOwnProperty method instead without first testing if that is a good idea or not.

I suspect that the reason for using Object.prototype.hasOwnProperty.call is that in some browsers, host objects don't have a hasOwnProperty method, using call and the built–in method is an alternative. However, doing so generically doesn't seem like a good idea for the reasons noted above.

Where host objects are concerned, the in operator can be used to test for properties generally, e.g.

var o = document.getElementsByTagName('foo');

// false in most browsers, throws an error in Internet Explorer 6, and probably 7 and 8
o.hasOwnProperty('bar');

// false in all browsers
('bar' in o);

// false (in all browsers? Do some throw errors?)
Object.prototype.hasOwnProperty.call(o, 'bar');

An alternative (tested in Internet Explorer 6 and others):

function ownProp(o, prop) {

  if ('hasOwnProperty' in o) {
    return o.hasOwnProperty(prop);

  } else {
    return Object.prototype.hasOwnProperty.call(o, prop);
  }
}

That way you only specifically call the built–in hasOwnProperty where the object doesn't have it (inherited or otherwise).

However, if an object doesn't have a hasOwnProperty method, it's probably just as suitable to use the in operator as the object likely doesn't have an inheritance scheme and all properties are on the object (that's just an assumption though), e.g. the in operator is a common (and seemingly successful) way of testing for DOM object support for properties.

Selfwill answered 18/8, 2012 at 13:29 Comment(4)
Thanks. Object.prototype.hasOwnProperty.call(o, 'bar') isn't working in FF 18.0 (at least in my case). So I decided to use ('bar' in o) -- and it helped.Rabi
@Rabi in does not perform a hasOwnProperty() lookup, I suspect the property you were looking for existed on the prototype chain.Czarra
This is an interesting example from eslint.org/docs/rules/no-prototype-builtins: For example, it would be unsafe for a webserver to parse JSON input from a client and call hasOwnProperty directly on the resulting object, because a malicious client could send a JSON value like {"hasOwnProperty": 1} and cause the server to crash.Titrate
Sure, but it would be wise to test or validate any client–supplied JSON with a JSON schema to prevent such issues, even if your concern was just data quality. And it should not cause the server to crash. :-)Selfwill
V
16

JavaScript does not protect the property name hasOwnProperty

If the possibility exists that an object might have a property with this name, it is necessary to use an external hasOwnProperty to get correct results:

You can copy paste the below code snippets to your browsers console to get better understanding

var foo = {
  hasOwnProperty: function() {
    return false;
  },
  bar: 'I belong to foo'
};

Always returns false

foo.hasOwnProperty('bar'); // false

Use another Object's hasOwnProperty and call it with this set to foo

({}).hasOwnProperty.call(foo, 'bar'); // true

It's also possible to use the hasOwnProperty property from the Object prototype for this purpose

Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
Viewing answered 15/8, 2017 at 12:45 Comment(1)
The point you are making has already been made in the accepted answer, except that there the override of hasOwnProperty returns true.Astray
H
4

The information given in both the first two answers (by date) is spot on. However, the use of:

('propertyName' in obj)

gets mentioned a few times. It should be noted that the hasOwnProperty implementations will return true only if the property is directly contained on the object being tested.

The in operator will inspect down through the prototype chain too.

This means that instance properties will return true when passed to hasOwnProperty where as the prototype properties will return false.

Using the in operator both instance and prototype properties will return true.

Hoppe answered 15/8, 2014 at 15:25 Comment(0)
Z
4

In addition to the rest of the answers here, note that you can use the new method Object.hasOwn (supported in most browsers and soon will be supported in the rest of them) instead of Object.hasOwnProperty.call as it allows you to write a terser and shorter code.

More about Object.hasOwn - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn

Browser compatibility - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn#browser_compatibility

Zeralda answered 28/9, 2021 at 13:20 Comment(0)
G
0

it's much more simple with:

let foo = Object.create(null);
if (foo.bar != null) {
    console.log('object foo contains bar property in any value and 
    type, except type undefined and null');
    // bar property can exist in object foo or any object of the prototype chain
}
Gusta answered 9/9, 2021 at 15:20 Comment(1)
Please provide additional details in your answer. As it's currently written, it's hard to understand your solution.Fremitus

© 2022 - 2024 — McMap. All rights reserved.