2

Let's consider the code below:

// Let's create a constructor "Point".

let Point = function(x,y) { this.x = x; this.y = y; };
Point.prototype = { x:null, y:null, print: function() { console.log("(" + this.x + "," + this.y + ")")} };

let p = new Point(1,2);
p.print();
console.log(Object.getPrototypeOf(p)); // => { x: null, y: null, print: [Function: print] }
console.log(Point.prototype === Object.getPrototypeOf(p)); // => true
console.log(p.constructor); // => Object
console.log(p.constructor.name); // => Object
console.log(p.constructor === Point); // => false
console.log(p.constructor === Object); // => true
console.log(p.prototype); // undefined
console.log(p instanceof Point); // => true
console.log(typeof p); // => Object
console.log();

// Let's create the constructor "Pigment" that derives from "Point".

let Pigment = function(x,y,c) {
    Point.call(this, x, y);
    this.color = c;
};
Pigment.prototype = new Point;
Pigment.prototype.paint = function () {
    console.log(this.color);
};

let pi = new Pigment(1,2,'red');
console.log(pi);
pi.print();
pi.paint();
console.log(Object.getPrototypeOf(pi)); // => (Pigment) { x: undefined, y: undefined, paint: [Function] }
console.log(pi instanceof Object); // => true
console.log(pi instanceof Point); // => true
console.log(pi instanceof Pigment); // => true
console.log(pi.constructor === Object); // => true
console.log(pi.__proto__); // => (Pigment) { x: undefined, y: undefined, paint: [Function] }
console.log(pi.__proto__.__proto__); // => (Point) { x: null, y: null, print: [Function: print] }
console.log(pi.print); // => [Function: print]
console.log(pi.__proto__ === Object.getPrototypeOf(pi)); // => true
console.log(pi.__proto__ == Pigment.prototype); // => true
console.log(pi.__proto__.__proto__ === Point.prototype); // => true

The prototype of the constructor "Point" is :

{
    x:null,
    y:null,
    print: function() { console.log("(" + this.x + "," + this.y + ")")}
}

The prototype of the constructor "Pigment" is an instance of "Point" :

Pigment.prototype = new Point;

Therefore I expect the prototype associated to the constructor "Pigment" to include the property "print". However, it is not the case. Indeed:

console.log(pi.__proto__);

Prints:

{ x: undefined, y: undefined, paint: [Function] }

Why is the property "print" missing?

--EDIT--

The example below works as expected :

var util = require("util");

function Person(age) {
    this.age = age;
}
Person.prototype = {
    age: null,
    print : function(){
        console.log("This person is " + this.age + " years old.");
    }
};

function Student(age, level) {
    Person.call(this, age);
    this.level = level;
}

Student.prototype = new Person;
Student.prototype.level = null;
Student.prototype.talk = function () {
    console.log("I talk");
};


Student.prototype.constructor = Student;
var b = new Student(10, 5);
b.print();
console.log(b.constructor);
console.log("b.proto:\n" + util.inspect(b.__proto__) + "\n");
console.log("b.proto.proto:\n" + util.inspect(b.__proto__.__proto__) + "\n");

Please note the added line:

Student.prototype.constructor = Student;

The output is:

This person is 10 years old.
[Function: Student]
b.proto:
Student {
  age: undefined,
  level: null,
  talk: [Function],
  constructor: [Function: Student] }

b.proto.proto:
{ age: null, print: [Function: print] }

This is correct.

Now, let's do what MeteorZero suggested: let's replace

Student.prototype = new Person;

By:

Student.prototype = Person.prototype;

Then, the result is:

This person is 10 years old.
[Function: Student]
b.proto:
Student {
  age: null,
  print: [Function: print],
  level: null,
  talk: [Function],
  constructor: [Function: Student] }

b.proto.proto:
{}

This is not what we expect.

Denis Kertios
  • 73
  • 1
  • 5

1 Answers1

1

Your assumption here is wrong Pigment.prototype = new Point;. You have assigned new Point object for Pigment.prototype not Point.prototype object. I have modified your assignment so print function is available now

// Let's create a constructor "Point".

let Point = function(x,y) { this.x = x; this.y = y; };
Point.prototype = { x:null, y:null, print: function() { console.log("(" + this.x + "," + this.y + ")")} };

let p = new Point(1,2);
p.print();
console.log(Object.getPrototypeOf(p)); // => { x: null, y: null, print: [Function: print] }
console.log(Point.prototype === Object.getPrototypeOf(p)); // => true
console.log(p.constructor); // => Object
console.log(p.constructor.name); // => Object
console.log(p.constructor === Point); // => false
console.log(p.constructor === Object); // => true
console.log(p.prototype); // undefined
console.log(p instanceof Point); // => true
console.log(typeof p); // => Object
console.log();

// Let's create the constructor "Pigment" that derives from "Point".

let Pigment = function(x,y,c) {
    Point.call(this, x, y);
    this.color = c;
};
// Pigment.prototype = new Point;
Pigment.prototype = Point.prototype;
Pigment.prototype.paint = function () {
    console.log(this.color);
};

let pi = new Pigment(1,2,'red');
console.log(pi);
pi.print();
pi.paint();
console.log(Object.getPrototypeOf(pi)); // => (Pigment) { x: undefined, y: undefined, paint: [Function] }
console.log(pi instanceof Object); // => true
console.log(pi instanceof Point); // => true
console.log(pi instanceof Pigment); // => true
console.log(pi.constructor === Object); // => true
console.log("pi.__proto__::", pi.__proto__); // => (Pigment) { x: undefined, y: undefined, paint: [Function] }
console.log(pi.__proto__.__proto__); // => (Point) { x: null, y: null, print: [Function: print] }
console.log(pi.print); // => [Function: print]
console.log(pi.__proto__ === Object.getPrototypeOf(pi)); // => true
console.log(pi.__proto__ === Pigment.prototype); // => true
console.log(pi.__proto__ === Point.prototype); // => true
hoangfin
  • 667
  • 7
  • 16
  • Yes, I tried this... however, it breaks (at least from what I understand) the chain of prototypes. The code `console.log(pi.__proto__.__proto__);` prints `{}`. – Denis Kertios May 18 '17 at 16:07
  • Yes It does break because you have set it wrong from beginning. – hoangfin May 18 '17 at 16:08
  • if you want `console.log(pi.__proto__.__proto__ === Point.prototype); // => true` then remove one `__proto__` then you'll have `console.log(pi.__proto__ === Point.prototype); // => true` – hoangfin May 18 '17 at 16:11
  • So what is the proper way to implement the inheritance ? I tried many ways, but none of them seems to work as expected. – Denis Kertios May 18 '17 at 16:14
  • The way I did. You want Pigment extend from Point then `Pigment.prototype = Point.prototype` – hoangfin May 18 '17 at 16:15
  • [this](http://stackoverflow.com/questions/34050143/how-does-inheritance-work-in-es5-javascript) may help you understand more about prototype and inheritance – hoangfin May 18 '17 at 16:19
  • @ MeteorZero Sorry, but the solution that you suggest breaks the chain of prototypes. I have edited my original post to illustrate this point. – Denis Kertios May 18 '17 at 18:36