Why does hasOwnProperty not recognise functions on an object's prototype?
Asked Answered
C

2

16

I understand that the hasOwnProperty method in JavaScript exists to identify properties only of the current type, but there is something in the prototype chain here that is confusing to me.

Let us imagine that I define a type called Bob, and assign two child functions to my Bob type in two different ways:

function Bob()
{
    this.name="Bob"; 
    this.sayGoodbye=function()
    {
        console.log("goodbye");   
    }
}

Bob.prototype.sayHello= function()
{
    console.log("hello");   
}

Now aside from having access to closure scope in the case of sayGoodbye, it seems to me that both functions belonging to the Bob class should be more or less equal. However, when I look for them with hasOwnProperty they are not the same as far as JavaScript is concerned:

var myBob = new Bob();
console.log( myBob.name ); // Bob, obviously 
console.log( myBob.hasOwnProperty("sayHello"));  // false
console.log( myBob.hasOwnProperty("sayGoodbye")); // true
console.log( "sayHello" in myBob ); // true

What is happening here in terms of scope? I could not create an instance of the Bob type without having the sayHello() and sayGoodbye() properties connected to it, so why is the prototype method a second class citizen as far as hasOwnProperty is concerned? Is Bob.prototype a type that exists somehow independently of the Bob type, from which Bob inherits everything?

Cuccuckold answered 17/3, 2014 at 0:56 Comment(10)
hasOwnProperty exists only to check the object itself for properties, it explicitly does not walk up the prototype chain, as that would defeat the purpose.Sumptuary
What I was looking for clarification on is why properties on a type's own prototype would not be identified by hasOwnProperty.Cuccuckold
Property access has nothing to do with scope, it is entirely different.Hayward
@Cuccuckold - The real answer is because that's the way hasOwnProperty() was designed. It only checks properties directly on the object, not anywhere in the prototype chain. I can see a rationale for a different function that tells you if the property is on the object or in it's own prototype, but that is not what .hasOwnProperty() was written to do. You could write such a function.Ylangylang
@jfriend00— typeof will suite for most cases, but if traversing the [[Prototype]] chain is required, then it is dependent on one of getPrototyeOf, __proto__ or that the constructor property and constructor.prototoype are accurate. But I don't see that there's much benefit to that beyond that provided by typeof.Hayward
@Hayward - it depends upon what the OP is really trying to do. My guess is that there's probably a better way to solve their issue entirely if they explained what the actual problem is.Ylangylang
@Ylangylang my exact goal here is to improve my understanding of how JavaScript's scope and inheritance stuff works, which still manages to be a regular source of surprises to me after all these years.Cuccuckold
@glenatron—step one is recognising that scope has nothing to do with property access. The first relates to resolution of variables in a lexical environment, the other relates to property name resolution on an object and its [[Prototype]] chain.Hayward
@Cuccuckold - The reason I asked about the actual problem is that I've encountered many reasons to use .hasOwnProperty() the way it works and many reasons to see if the object has a property in any way, but never encountered a reason to use the function you're asking about in real code.Ylangylang
@Ylangylang The structure of the actual case isn't too different to my example- I have classes that have a set of properties, some of which are 'own' properties others are on the class prototype ( but no higher up the chain ) and as both seem to me ( with a background in more traditional object oriented languages ) to be part of the same class definition, I wasn't sure why I could only treat some as properties of an instance of the type. As it is I am just using in to do the same job, which is fine here. Trying to understand rather than just fix the problem.Cuccuckold
I
14

I think you're confusing a few concepts here. Let's take this quote from the MDN:

Every object descended from Object inherits the hasOwnProperty method. This method can be used to determine whether an object has the specified property as a direct property of that object; unlike the in operator, this method does not check down the object's prototype chain.

So that's the key here. When you use new JavaScript will assign a brand new object to this and return it, that's what an instance is. Any property declared inside the constructor is an own property. Properties declared on the prototype are not, since they are shared with other instances of the same object.

And a prototype is also an Object, for example:

Bob.prototype.hasOwnProperty("sayHello"); //=> true

myBob.constructor.prototype.hasOwnProperty("sayHello"); //=> true
Inspector answered 17/3, 2014 at 1:3 Comment(5)
Does that mean I could instantiate a new Bob.prototype that would have access to all the shared properties of the Bob type but not its constructor? Assuming I was sufficiently drunk that it seemed like a good idea.Cuccuckold
Yes, that how you do inheritance, NewObject.prototype = Object.create(Bob.prototype)Inspector
@Cuccuckold - Bob.prototype already exists as an object. You don't have to instantiate one to read what's in it.Ylangylang
@Inspector that's not how I do inheritance, but it is very probably how I should do inheritance. Normally I'd just say James.prototype = new Bob()Cuccuckold
Well, yes that's how you'd do it in old browsers, but it's a bit hacky in a way... Check the polyfill here developer.mozilla.org/en-Inspector
H
4

I understand that the hasOwnProperty method in JavaScript exists to identify properties only of the current type

That is not correct. hasOwnProperty identifies own properties of an object, that is, properties of the object itself. It does not consider inherited properties on an object's [[Prototype]] chain.

e.g.

var foo = {name: 'foo'};

// Check for an own property
foo.hasOwnProperty('name'); // true

The object foo also inherits a toString method from Object.prototype, but it's not an "own" property:

typeof foo.toString             // function
foo.hasOwnProperty('toString'); // false
Hayward answered 17/3, 2014 at 1:17 Comment(1)
I got that regarding the longer inheritance chain. The specific confusion I had was where one had a property declared through the foo.prototype.name specifically, so the property only exists on type foo and it's children. Although the definition of own properties explains where I went wrong, I don't think it would be illogical if all properties uniquely belonging to foo and its children were considered properties of foo rather than only those within the function declaration.Cuccuckold

© 2022 - 2024 — McMap. All rights reserved.