JavaScript Inheritance: When a Constructor Has Arguments

Using pure JavaScript for inheritance, I usually do this:

function A() {} A.prototype.run = function () {}; function B() {} B.prototype = new A; B.prototype.constructor = B; 

Since there are no arguments to the constructor, the new A has no right to complain. Now I have not found a way to do inheritance if the constructor has arguments. For example,

 function A(x, y) {} A.prototype.run = function () {}; function B(x, y) {} B.prototype = new A; B.prototype.constructor = B; 

I could pass some arbitrary values, for example:

 B.prototype = new A(null, null); 

In some cases, I may need to check x and y in constructor A. In some extreme cases, I need to throw errors when checking x or y. Then there is no way for B to inherit from A using the new A.

Any suggestions?

Thank!

+42
javascript inheritance prototype-programming
Sep 23 '11 at 18:44
source share
4 answers

Well, if you want to make a B.prototype object that inherits from A.prototype without executing the A constructor in order to avoid all possible side effects, you can use the dummy object constructor to do this, for example

 function tmp() {} tmp.prototype = A.prototype; B.prototype = new tmp(); B.prototype.constructor = B; 

You can create a function to encapsulate the logic of creating this new object, for example:

 function inherit(o) { function F() {}; // Dummy constructor F.prototype = o; return new F(); } //... B.prototype = inherit(A.prototype); B.prototype.constructor = B; 

If you are targeting modern browsers, you can use the ECMAScript 5 Object.create for the same purpose, for example:

 B.prototype = Object.create(A.prototype); B.prototype.constructor = B; //.. 
+19
Sep 23 '11 at 18:58
source share

The problem is that you cannot easily create a prototype object for B , since the call to constructor A cannot be performed. This is because the parameters for the unknown constructor are executed before the execution of new B To create a prototype for B that references prototype A , you need a constructor-dummy constructor function.

 B.prototype = (function(parent){ function protoCreator(){}; protoCreator.prototype = parent.prototype; // Construct an object linking to A.prototype without calling constructor of A return new protoCreator(); })(A); 

Once you have the prototype object for B installed, you need to provide a call to constructor A in constructor B

 function B(x, y) { // Replace arguments by an array with A arguments in case A and B differ in parameters A.apply(this, arguments); } 

Now you can create an instance of B by calling new B(x, y) .

To fully enable parameter checking in A see jsFiddle .

In the source code, you set B.prototype.constructor = B I do not understand why you are doing this. The constructor property does not affect the inheritance hierarchy for which the prototype property corresponds. If you want to have the named constructor contained in the constructor property, you need to extend the code a bit above:

 // Create child prototype – Without calling A B.prototype = (function(parent, child){ function protoCreator(){ this.constructor = child.prototype.constructor }; protoCreator.prototype = parent.prototype; return new protoCreator(); })(A, B); 

Using the first B.prototype definition, you will get the following results:

 var b = new B(4, 6); b.constructor // A console.info(b instanceof A); // true console.info(b instanceof B); // true 

In the advanced version you will receive:

 var b = new B(4, 6); b.constructor // B console.info(b instanceof A); // true console.info(b instanceof B); // true 

The reason for the other conclusion is that instanceof follows the entire B prototype chain and tries to find a suitable prototype object for A.prototype or B.prototype (in another call). The prototype b.constructor refers to the function that was used to determine the prototype of the instances. If you are wondering why it does not point to protoCreator , this is because its prototype was overwritten by A.prototype during the creation of B.prototype . The extended definition shown in the updated example corrects this constructor property to indicate a more appropriate (as, probably, more expected) function.

For daily use, I would recommend abandoning the idea of ​​using the entire constructor property of instances. Use instanceof instead, as its results are more predictable / expected.

+6
Sep 23 '11 at 19:08
source share

Consider this:

 function B( x, y ) { var b = Object.create( new A( x, y ) ); // augment b with properties or methods if you want to return b; } 

And then

 var b = new B( 12, 13 ); 

Now b inherits from an instance of A , which in turn inherits from A.prototype .

Live demo: http://jsfiddle.net/BfFkU/




Object.create not implemented in IE8, but it can be easily done manually:

 if ( !Object.create ) { Object.create = function ( o ) { function F() {} F.prototype = o; return new F(); }; } 

This can be placed inside the ie8.js file, which is only loaded for IE8 and below via conditional comments.

+5
Sep 23 '11 at 20:55
source share

Although this is an old topic, I thought I would answer anyway. Two ways to do this:

Although the Pseudo Classical method is most popular, it has its drawbacks, since it needs to call the parent constructor once in the child constructor and once when inheriting the prototype. In addition, the child prototype will contain all the properties of the parent constructor, which in any case will be overwritten when the child constructor is called. My personal choice Prototype inheritance .

1. Pseudo-classical inheritance:

 function A(x, y) {} A.prototype.run = function () {}; function B(x, y) { A.call(this,x,y); } B.prototype = new A(); B.prototype.constructor = B; 

2. Prototype inheritance:

 function A(x, y) {} A.prototype.run = function () {}; function B(x, y) { A.call(this,x,y); } B.prototype = Object.create(A.prototype); B.prototype.constructor = B; 
+3
Feb 19 '16 at 7:07
source share



All Articles