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:
You don't want to use new Human
to create Male.prototype
.
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:
[[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"
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)
returntrue
but not inHuman.isPrototypeOf(albert)
(it returnfalse
) sinceMale.prototype
is an instance ofHuman
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.