2

For below hierarchy of function constructors,

enter image description here

below are the instances created.

enter image description here

When Javascript sees,

mark = new WorkerBee;

an object with members name, dept,projects and __proto__ are created. This object(value of this) is passed to WorkerBee constructor.

Does Employee constructor get executed before WorkerBee constructor?

overexchange
  • 15,768
  • 30
  • 152
  • 347
  • 1
    Your inheritance pattern is "wrong". You won't have properties created in each instance of your subclasses. Lookup and read about JS prototypical inheritance – Amit Aug 26 '15 at 10:31
  • @Amit OK. Can you correct me? – overexchange Aug 26 '15 at 17:14
  • From where are these graphics? Did you create them yourself? – Bergi Aug 26 '15 at 17:53
  • @Bergi Amidst learning hierarchy and inheritance [here](http://www.cs.rit.edu/~atk/JavaScript/manuals/jsobj/index.htm#1035230), I had this diagrams. Am a beginner. – overexchange Aug 26 '15 at 17:59
  • @overexchange: Amazing. Looks like that page is a copy from the netscape documentation (remember [Netscape](https://en.wikipedia.org/wiki/Netscape)? probably not). **Last updated in 1998**. Please throw it away - it's full of bad code ([see this post for details](http://stackoverflow.com/a/12593269/1048572)). You will find an [updated guide on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript) which was recently fixed (it's a wiki). – Bergi Aug 26 '15 at 18:24

2 Answers2

2

The most common JavaScript prototypical inheritance pattern then resembles your code can be seen on MDN.

The essence is that you need to assign a prototype for your inheriting types that is a new object with the prototype set to the required base type. Then you also call the base type's constructor function inside the inheriting constructor. For completeness and to maintain proper structure, you also reset the constructor of the newly created prototype object (which doesn't point to the correct function if you don't).

After creating the prototype object, you can add type-level functions to it (It can also be done in the Object.create call, but personally I like that less)

The entire code would look like (Also added optional constructor initialization values):

function Employee(name, dept) {
  this.name = name || '';
  this.dept = dept || 'general';
}

function WorkerBee(name, dept) {
  Employee.call(this, name, dept);
  this.projects = [];
}
WorkerBee.prototype = Object.create(Employee.prototype);
WorkerBee.prototype.constructor = WorkerBee;
WorkerBee.prototype.addProject = function(project) { this.projects.push(project); };

// Same for Manager...

function SalesPerson(name) {
  WorkerBee.call(this, name, 'sales');
  this.quota = 100;
}
SalesPerson.prototype = Object.create(WorkerBee.prototype);
SalesPerson.prototype.constructor = SalesPerson;

// Same for Engineer

var mark = new WorkerBee('Mark');
var noName = new WorkerBee();
var fred = new SalesPerson('Fred');

fred.addProject('Sell ice to an eskimo');

console.log(mark, noName, fred);

With ES2015 classes all that redundant code becomes much more concise:

'use strict'

class Employee {
  constructor(name, dept) {
    this.name = name || '';
    this.dept = dept || 'general';
  }
}

class WorkerBee extends Employee {
  constructor(name, dept) {
    super(name, dept);
    this.projects = [];
  }

  addProject(project) { this.projects.push(project) }
}

class SalesPerson extends WorkerBee {
  constructor(name) {
    super(name, 'sales');
    this.quota = 100;
  }
}

var mark = new WorkerBee('Mark');
var noName = new WorkerBee();
var fred = new SalesPerson('Fred');

fred.addProject('Sell ice to an eskimo');

console.log(mark, noName, fred);
Amit
  • 45,440
  • 9
  • 78
  • 110
  • i think your answer is going at different level, because you are saying `Object.create(Employee.prototype)` unlike my example, `new Employee`. Please read this [reference](http://www.cs.rit.edu/~atk/JavaScript/manuals/jsobj/index.htm#1035230) before you answer. – overexchange Aug 26 '15 at 18:01
  • @overexchange: Yes, `Object.create` is how it should be done today. Really. Admittedly, that method is much younger than the manual you were reading. – Bergi Aug 26 '15 at 18:27
  • @overexchange - looks like that page is nearly 20 years old. At the time `Object.create` didn't exist, and a lot has changed since then. It's not at all hard to polyfill `Object.create` as you can see in the link in my answer, but I guess 20 years ago the understand of the technology wasn't mature enough and so the solution is inferior. For example, as explained in the link I provided, create an instance of an object (say Employee) to serve as the prototype results in an instance that has properties in a place they don't belong (such as a name value inside the prototype tree). – Amit Aug 26 '15 at 18:46
  • @Amit 1) Except code being 20 years old, what was the problem in my code? Why `WorkerBee.prototype = Object.create(Employee.prototype)` but not `WorkerBee.prototype = new Employee`? Is my code inefficient? ###2) your class based approach makes my life easier, Good bye to the feel of prototypical inheritance!!! – overexchange Aug 27 '15 at 04:16
  • @overexchange: No, your code is not inefficient, it's simply wrong and not working. This is not class-based versus prototype-based, but class-based design implemented *through* prototypical inheritance. We're just showing you how to do it correctly, without using any different idea. – Bergi Aug 27 '15 at 04:26
  • @Bergi Below *Quentin* says the *The Employee constructor is executed when you call `WorkerBee.prototype = new Employee.`*. Is creation of only `projects` field an issue? So, what is wrong in my code? – overexchange Aug 27 '15 at 04:33
  • @overexchange: Quentin only says that this is what happens in your code, and technically answers your question which one comes first. He does also say that it is not what you want - because it is wrong. See the reasons I've detailed in the comments all around there, and the links I've posted. Yes, the `projects` array becomes a problem when placed on the prototype. – Bergi Aug 27 '15 at 04:36
0

The Employee constructor is executed when you call WorkerBee.prototype = new Employee.

This is before you say mark = new WorkerBee;, so technically the answer is "yes", but that probably isn't what you mean.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Are you saying that *__proto__* property of `mark` will point to memory created by `WorkerBee.prototype = new Employee`? So, only `projects` field will be created when you say `new WorkerBee` but not `name` and `dept`? – overexchange Aug 26 '15 at 18:16
  • @overexchange: Exactly. And that's the problem with this code, the reason why it should not be used. – Bergi Aug 26 '15 at 18:25
  • @Bergi am still not clear about the problem with my code. I know it is 20 years old. – overexchange Aug 26 '15 at 19:24
  • @overexchange: It's missing the `super` calls to initialise fields that the parent constructor expects - see [this example](http://stackoverflow.com/q/4425318/1048572). Hell, it's even right there in your demo code: `fred` and all other `Engineer`s have exactly the same `projects` array. Assign a task to either of them and it will pop up in all of them. – Bergi Aug 26 '15 at 19:46
  • @Bergi why would I need super call, when WorkerBee.prototype = new Employee is already executed. Are you saying that I should forget prototypical inheritance approach and use class based approach? Because Amit's second approach in his answer does not require knowledge of prototypical inheritance. – overexchange Aug 27 '15 at 04:02
  • @overexchange: No, Amiit's approach still does require knowledge of prototypical inheritance. It's just that the (corrected) pattern became so common and popular that it got its own syntactic sugar in the language - the prototype-based inheritance is still there. – Bergi Aug 27 '15 at 04:30
  • @overexchange: You need the super call because the purpose of the constructor is to initialise instances - all instances, individually, every time one is constructed. It should not be executed to initialise a prototype object which is going to be shared (by inheritance) with all instances of the subclass. The prototype object should not be an instance. – Bergi Aug 27 '15 at 04:32
  • @overexchange: You may also want to read http://stackoverflow.com/a/17393153/1048572/Benefits-of-using-Object.create-for-inheritance if the other question I linked was not enough to persuade you. – Bergi Aug 27 '15 at 04:34
  • @Bergi Programmer using class based approach does not require knowledge of prototypical inheritance is under hood job, which is none of my business to bother. – overexchange Aug 27 '15 at 04:36
  • @overexchange: Well if you don't bother to understand what goes on under the hood, just take our advise and write the code as we tell you to do. – Bergi Aug 27 '15 at 04:40