2

If I run this piece of JavaScript code in Firefox:

function Human() {

}

function Engineer(diploma) {
    this.diploma = diploma;
}

Engineer.prototype = new Human();// Line A1
Engineer.prototype.constructor = Engineer;
Engineer.prototype.getDiploma = function() {
    alert(this.diploma);
};
var engineer = new Engineer("Bridges and Roads");
engineer.getDiploma();
var human = new Human();
human.getDiploma(); // Line A2

the line marked as "A2" will generate an error in the Firefox console:

TypeError: human.getDiploma is not a function

Note also that, on line A1, I've used "new" to simulate that Engineer inherits from Human. This can be tested in the following JSFiddle:

http://jsfiddle.net/RMWdh/1/

Now I change the A1 line like so:

function Human() {

}

function Engineer(diploma) {
    this.diploma = diploma;
}

Engineer.prototype = Human.prototype;// Line B1
Engineer.prototype.constructor = Engineer;
Engineer.prototype.getDiploma = function() {
    alert(this.diploma);
};
var engineer = new Engineer("Bridges and Roads");
engineer.getDiploma();
var human = new Human();
human.getDiploma(); // Line B2

Note that A1 line has been replaced by the B1 line. The rest of the code is the same. This time, if I run it, there's no error in the Firefox console, but I will get one alert saying "Bridges and Roads" (which is the call to engineer.getDiploma()), and another alert saying "undefined" (which is the result of the B2 line). This can also be checked on JSFiddle, here:

http://jsfiddle.net/RMWdh/2/

My question is: why this difference? What's the difference between doing this:

 Engineer.prototype = new Human();

and this:

 Engineer.prototype = Human.prototype;
Shivan Dragon
  • 15,004
  • 9
  • 62
  • 103
  • possible duplicate of [Why can't I call a prototyped method in Javascript?](http://stackoverflow.com/questions/12500637/why-cant-i-call-a-prototyped-method-in-javascript) – Bergi Nov 17 '13 at 13:24
  • Hi, it's a little late but if you want diploma and getDiploma to be members of Human you should define diplama in the Human body with this.deploma, define getDiploma on Human.prototype and get ownership of diploma when creating an Engeneer instance by adding `Human.call(this,arguments);` in the Engeneer constructor function. Change the signature of Human to Human(diploma). More info on prototypes and inheritance can be found here: http://stackoverflow.com/a/16063711/1641941 – HMR Nov 17 '13 at 13:41

2 Answers2

3

The latter simply copies the reference, making both "Engineers are Humans" and "Humans are Engineers" true. That isn't typically the desired effect.

Engineer.prototype = Human.prototype;
var human = new Human();
/*
  engineer ->
    (Engineer.prototype & Human.prototype) ->
      Object.prototype
*/

var human = new Human();
console.log('getDiploma' in human);     // true
console.log(human instanceof Engineer); // true

The former, on the other hand, only establishes that "Engineers are Humans." This allows Engineers to keep their own identity and logic separate from other Humans. In this case, including .getDiploma().

Engineer.prototype = new Human();
var engineer = new Engineer("Bridges and Roads");
/*
  engineer ->
    Engineer.prototype ->
      Human.prototype ->
        Object.prototype
*/

var human = new Human();
console.log('getDiploma' in human);     // false
console.log(human instanceof Engineer); // false

You can also use Object.create() to establish the prototype chain without needing to call the constructor:

Engineer.prototype = Object.create(Human.prototype);
Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
  • Ok, but: a. why, in the latter case, do I get undefined when calling human.getDiploma() ? and b. does it mean that each time I do "new Human" a new clone of its prototype is made? – Shivan Dragon Nov 17 '13 at 13:11
  • @ShivanDragon A) You see `undefined` because `human.getDiploma()` is attempting to `alert(human.diploma)`, which was never set. An object can inherit from `Engineer.prototype` without ever calling the `Engineer()` constructor function -- `Object.create(Engineer.prototype)` included. – Jonathan Lonowski Nov 17 '13 at 13:22
  • @ShivanDragon B) Not a clone per-se, but they do inherit directly from `Human.prototype`, yes. Inheritance in JavaScript is managed through `[[Prototype]]` properties (exposed as `__proto__` in some browsers). When encountering a property accessor/member operator, the JavaScript engine can follow the chain of `[[Prototype]]` references until it finds the property or the end of the chain. – Jonathan Lonowski Nov 17 '13 at 13:24
0

Your problem is prototype inheritance:

with line A2 you're calling

human.getDiploma()

but getDiploma doesn't appear on the prototype of Human.

Engineer inherits the object Human as it's prototype, but Human doesn't inherit anything from Engineer.

if you made getDiploma() a method on Human, you'd have this working:

function Human() {

}

Human.prototype.getDiploma = function() {
    alert(this.diploma);
};

function Engineer(diploma) {
    this.diploma = diploma;
}

Engineer.prototype = Human.prototype;// Line B1
Engineer.prototype.constructor = Engineer;

var engineer = new Engineer("Bridges and Roads");
engineer.getDiploma(); // "Bridges and Roads"
var human = new Human();
human.getDiploma(); // "undefined"
Mikebert4
  • 156
  • 4