简体   繁体   中英

.isPrototypeOf() and .hasOwnProperty() method confusion

Let say i have this code:

 // Male will inherit ALL of the Human properties function Human(x, y) { // Following properties will be inherited this.name = x; this.age = y; this.test = "Test 1"; } // Following properties will ALSO be inherited Human.prototype.citizen = "USA"; Human.prototype.employer = "Google"; Human.prototype.test = "Test 2"; function Male(x, y) { // Following properties will be the own properties of Male instances this.name = x; this.age = y; this.gender = "Male"; } // Inheritance - Connecting Male object with Human object Male.prototype = new Human(); // no arguments are passed Male.prototype.constructor = Male; // correcting constructor property var albert = new Male("Albert", 25); 

Then, i want to do some testing on the code

Human.isPrototypeOf(albert); // I expect it to return TRUE

But it return FALSE, why is that?

and, for the following test

Human.hasOwnProperty("age"); // /i expect it to return TRUE

But it return FALSE, why is that?

Thanks,

Edit My questions are slightly different with the other question since it's also talk about prototype chain.

The Human function isn't in albert 's prototype chain. The object referenced by Human.prototype is:

Human.prototype.isPrototypeOf(albert); // true

Human.hasOwnProperty("age"); // /i expect it to return TRUE

The Human function doesn't have an age property. Instances created with it by new do:

new Human().hasOwnProperty("age"); // true

Side note: The way you're setting up the inheritance chain is common and shown in a lot of examples, but incorrect in two ways:

  1. You don't want to use new Human to create Male.prototype .

  2. You do want to call Human from Male :

So:

function Male(x, y) {
    // Give Human its chance to initialize the object (#2)
    Human.call(this, x, y);
    // ...
}

// Don't use new Human to create the prototype (#1)
Male.prototype = Object.create(Human.prototype);
Male.prototype.constructor = Male;

The reason you don't use new Human to create the prototype for Male is simple: Human expects arguments, but you don't have any to give it.

Here's an updated ES5 and earlier version of that code:

 function Human(name, age) { // Argument names should be meaningful this.name = name; this.age = age; this.test = "Test 1"; } Human.prototype.citizen = "USA"; Human.prototype.employer = "Google"; Human.prototype.test = "Test 2"; function Male(name, age) { Human.call(this, name, age); this.gender = "Male"; } Male.prototype = Object.create(Human.prototype); Male.prototype.constructor = Male; var albert = new Male("Albert", 25); console.log(Human.prototype.isPrototypeOf(albert)); // true console.log(new Human().hasOwnProperty("age")); // true 

Or of course, use ES2015+ (transpiling if your target doesn't support it yet):

 // THIS SNIPPET REQUIRES A BROWSER WITH ES2015+ SUPPORT class Human { constructor(name, age) { this.name = name; this.age = age; this.test = "Test 1"; } } Human.prototype.citizen = "USA"; Human.prototype.employer = "Google"; Human.prototype.test = "Test 2"; class Male extends Human { constructor(name, age) { super(name, age); this.gender = "Male"; } } let albert = new Male("Albert", 25); console.log(Human.prototype.isPrototypeOf(albert)); // true console.log(new Human().hasOwnProperty("age")); // true 


You've said you're trying to see how the chain works. Here's a diagram of what we have in memory after creating albert (with several details removed for simplicity):

+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+
         |                                                                      |
         \ +−−−−−−−−−−−−−−−−+                                                   |
Human−−−−−>|    function    |                                                   |
           +−−−−−−−−−−−−−−−−+                            +−−−−−−−−−−−−−−−−−−−−+ |
           | prototype      |−−−−−−−−−−−−−−−−−−−−−−−−−−−>|       object       | |    
           | name: "Human"  |                          / +−−−−−−−−−−−−−−−−−−−−+ |    
           +−−−−−−−−−−−−−−−−+                          | | constructor        |−+
                                                       | | citizen: "USA"     |
         +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+ | | employer: "Google" |
         |                                           | | | test: "Test 2"     |
         \ +−−−−−−−−−−−−−−−−+                        | | +−−−−−−−−−−−−−−−−−−−−+
Male−−−−−−>|    function    |                        | |
           +−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−+ | |
           | prototype      |−−−>|     object      | | |
           | name: "Male"   |  / +−−−−−−−−−−−−−−−−−+ | |
           +−−−−−−−−−−−−−−−−+  | | constructor     |−+ |
                               | | [[Prototype]]   |−−−+
           +−−−−−−−−−−−−−−−−+  | +−−−−−−−−−−−−−−−−−+
albert−−−−>|     object     |  |
           +−−−−−−−−−−−−−−−−+  |
           | name: "Albert" |  |
           | age: 25        |  |
           | gender: "Male" |  |
           | [[Prototype]]  |−−+
           +−−−−−−−−−−−−−−−−+

[[Prototype]] above is the name the spec uses for the "internal slot" of an object that contains its reference to its prototype object. In contrast, prototype , the property on functions (eg, Human.prototype ), is just a normal property of functions that points to the object that new will use as the [[Prototype]] of the new object it creates if you use that function with new .

Some notes on that diagram:

  • All functions have a [[Prototype]] internal slot that points to the object Function.prototype points to (omitted above for simplicity).
  • Human , the function, has a name property: "Human"
  • Male , the function, has a name property: "Male"
  • The object albert refers to has a name property: "Albert"
  • albert 's [[Prototype]] is Male.prototype ; Male.prototype 's [[Prototype]] is Human.prototype (and Human.prototype 's [[Prototype]] , not shown, is `Object.prototype).

In a comment you've said:

I just can't understand why after inheritance statement we can do Male.prototype.isPrototypeOf(albert) return true but not in Human.isPrototypeOf(albert) (it return false ) since Male.prototype is an instance of Human

Because Human , the function, is nowhere in albert 's prototype chain. Lets' look at albert 's prototype chain:

  • albert 's [[Prototype]] is Male.prototype
  • Male.prototype 's [[Prototype]] is Human.prototype
  • Human.prototype 's [[Prototype]] is Object.prototype
  • Object.prototype 's [[Prototype]] is null

As a diagram:

+−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−−−−−+ 
|    albert     |    | Male.prototype |    | Human.prototype |    |  Object.prototype   |
+−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−−−−−+ 
| [[Prototype]] |−−−>| [[Prototype]]  |−−−>| [[Prototype]]   |−−−>| [[Prototype]]: null |
+−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−−−−−−−−−−+

So Human , the function, is nowhere in that chain.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM