Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript inheritance: call super-constructor or use prototype chain?

Quite recently I read about JavaScript call usage in MDC

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/call

one linke of the example shown below, I still don't understand.

Why are they using inheritance here like this

Prod_dept.prototype = new Product(); 

is this necessary? Because there is a call to the super-constructor in

Prod_dept() 

anyway, like this

Product.call 

is this just out of common behaviour? When is it better to use call for the super-constructor or use the prototype chain?

function Product(name, value){   this.name = name;   if(value >= 1000)     this.value = 999;   else     this.value = value; }  function Prod_dept(name, value, dept){   this.dept = dept;   Product.call(this, name, value); }  Prod_dept.prototype = new Product();  // since 5 is less than 1000, value is set cheese = new Prod_dept("feta", 5, "food");  // since 5000 is above 1000, value will be 999 car = new Prod_dept("honda", 5000, "auto"); 

Thanks for making things clearer

like image 815
Jeremy S. Avatar asked Nov 11 '10 09:11

Jeremy S.


People also ask

Do you have to call super in constructor JavaScript?

Attempting to read super itself is a SyntaxError . In the constructor body of a derived class (with extends ), the super keyword may appear as a "function call" ( super(... args) ), which must be called before the this keyword is used, and before the constructor returns.

Is JavaScript prototype inheritance?

In JavaScript, an object can inherit properties of another object. The object from where the properties are inherited is called the prototype. In short, objects can inherit properties from other objects — the prototypes.

Is super () necessary JavaScript?

The fish class doesn't need super() because its “parent” is just the JavaScript Object. Fish is already at the top of the prototypal inheritance chain, so calling super() is not necessary — fish's this context only needs to include Object, which JavaScript already knows about.

How does inheritance work in JavaScript?

When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype.


2 Answers

The answer to the real question is that you need to do both:

  • Setting the prototype to an instance of the parent initializes the prototype chain (inheritance), this is done only once (since the prototype object is shared).
  • Calling the parent's constructor initializes the object itself, this is done with every instantiation (you can pass different parameters each time you construct it).

Therefore, you should not call the parent's constructor when setting up inheritance. Only when instantiating an object that inherits from another.

Chris Morgan's answer is almost complete, missing a small detail (constructor property). Let me suggest a method to setup inheritance.

function extend(base, sub) {   // Avoid instantiating the base class just to setup inheritance   // Also, do a recursive merge of two prototypes, so we don't overwrite    // the existing prototype, but still maintain the inheritance chain   // Thanks to @ccnokes   var origProto = sub.prototype;   sub.prototype = Object.create(base.prototype);   for (var key in origProto)  {      sub.prototype[key] = origProto[key];   }   // The constructor property was set wrong, let's fix it   Object.defineProperty(sub.prototype, 'constructor', {      enumerable: false,      value: sub    }); }  // Let's try this function Animal(name) {   this.name = name; }  Animal.prototype = {   sayMyName: function() {     console.log(this.getWordsToSay() + " " + this.name);   },   getWordsToSay: function() {     // Abstract   } }  function Dog(name) {   // Call the parent's constructor   Animal.call(this, name); }  Dog.prototype = {     getWordsToSay: function(){       return "Ruff Ruff";     } }      // Setup the prototype chain the right way extend(Animal, Dog);  // Here is where the Dog (and Animal) constructors are called var dog = new Dog("Lassie"); dog.sayMyName(); // Outputs Ruff Ruff Lassie console.log(dog instanceof Animal); // true console.log(dog.constructor); // Dog 

See my blog post for even further syntactic sugar when creating classes. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Technique copied from Ext-JS and http://www.uselesspickles.com/class_library/ and a comment from https://stackoverflow.com/users/1397311/ccnokes

like image 90
Juan Mendes Avatar answered Nov 15 '22 23:11

Juan Mendes


The ideal way to do it is to not do Prod_dept.prototype = new Product();, because this calls the Product constructor. So the ideal way is to clone it except for the constructor, something like this:

function Product(...) {     ... } var tmp = function(){}; tmp.prototype = Product.prototype;  function Prod_dept(...) {     Product.call(this, ...); } Prod_dept.prototype = new tmp(); Prod_dept.prototype.constructor = Prod_dept; 

Then the super constructor is called at construction time, which is what you want, because then you can pass the parameters, too.

If you look at things like the Google Closure Library you'll see that's how they do it.

like image 36
Chris Morgan Avatar answered Nov 16 '22 00:11

Chris Morgan