JavaScript Inheritance

I am trying to implement inheritance in javascript. I came up with a minimal code to support it.

function Base(){ this.call = function(handler, args){ handler.call(this, args); } } Base.extend = function(child, parent){ parent.apply(child); child.base = new parent; child.base.child = child; } 

Experts, please let me know if this will be enough or any other important issue that I may have missed. Based on similar issues, please suggest other changes.

Here is the full test script:

 function Base(){ this.call = function(handler, args){ handler.call(this, args); } this.superalert = function(){ alert('tst'); } } Base.extend = function(child, parent){ parent.apply(child); child.base = new parent; child.base.child = child; } function Child(){ Base.extend(this, Base); this.width = 20; this.height = 15; this.a = ['s','']; this.alert = function(){ alert(this.a.length); alert(this.height); } } function Child1(){ Base.extend(this, Child); this.depth = 'depth'; this.height = 'h'; this.alert = function(){ alert(this.height); // display current object height alert(this.a.length); // display parents array length this.call(this.base.alert); // explicit call to parent alert with current objects value this.call(this.base.superalert); // explicit call to grandparent, parent does not have method this.base.alert(); // call parent without overriding values } } var v = new Child1(); v.alert(); alert(v.height); alert(v.depth); 
+73
javascript
Sep 20 2018-11-11T00:
source share
13 answers

If you need inheritance, there are many, many libraries already offer this. At the very least, read them to find out where you are mistaken. But why invent? Two amazing JavaScript inheritance libraries that come to mind are klass and selfish. js (I used both, they are awesome.)

+14
Sep 20 2018-11-11T00:
source share

To implement javascript inheritance in ECMAScript 5 , you can define an object prototype and use Object.create for inheritance. You can also add / override properties as much as you want.

Example:

 /** * Transform base class */ function Transform() { this.type = "2d"; } Transform.prototype.toString = function() { return "Transform"; } /** * Translation class. */ function Translation(x, y) { // Parent constructor Transform.call(this); // Public properties this.x = x; this.y = y; } // Inheritance Translation.prototype = Object.create(Transform.prototype); // Override Translation.prototype.toString = function() { return Transform.prototype.toString() + this.type + " Translation " + this.x + ":" + this.y; } /** * Rotation class. */ function Rotation(angle) { // Parent constructor Transform.call(this); // Public properties this.angle = angle; } // Inheritance Rotation.prototype = Object.create(Transform.prototype); // Override Rotation.prototype.toString = function() { return Transform.prototype.toString() + this.type + " Rotation " + this.angle; } // Tests translation = new Translation(10, 15); console.log(translation instanceof Transform); // true console.log(translation instanceof Translation); // true console.log(translation instanceof Rotation); // false console.log(translation.toString()) // Transform2d Translation 10:15 
+132
Oct 10 '12 at 10:13
source share

I think Crockford’s decision is too complicated, as is John. It is much easier to get javascript inheritance than both of them describe. Consider:

 //Classes function A() { B.call(this); } function B() { C.call(this); this.bbb = function() { console.log("i was inherited from b!"); } } function C() { D.call(this); } function D() { E.call(this); } function E() { //instance property this.id = Math.random() } //set up the inheritance chain (order matters) D.prototype = new E(); C.prototype = new D(); B.prototype = new C(); A.prototype = new B(); //Add custom functions to each A.prototype.foo = function() { console.log("a"); }; B.prototype.bar = function() { console.log("b"); }; C.prototype.baz = function() { console.log("c"); }; D.prototype.wee = function() { console.log("d"); }; E.prototype.woo = function() { console.log("e"); }; //Some tests a = new A(); a.foo(); a.bar(); a.baz(); a.wee(); a.woo(); console.log(a.id); a.bbb(); console.log(a instanceof A); console.log(a instanceof B); console.log(a instanceof C); console.log(a instanceof D); console.log(a instanceof E);​ var b = new B(); console.log(b.id) 

I wrote a full description of the above solution on my blog .

+42
Apr 20 2018-12-12T00:
source share

As I played with JS objects, I found a more minimal solution :-) Enjoy!

 function extend(b,a,t,p) { b.prototype = a; a.apply(t,p); } 

Example

 function A() { this.info1 = function() { alert("A"); } } function B(p1,p2) { extend(B,A,this); this.info2 = function() { alert("B"+p1+p2); } } function C(p) { extend(C,B,this,["1","2"]); this.info3 = function() { alert("C"+p); } } var c = new C("c"); c.info1(); // A c.info2(); // B12 c.info3(); // Cc 
+11
Feb 03 '13 at 20:42
source share

Here is the simplest and I hope the easiest way to understand inheritance in JS. This example will be most useful for PHP programmers.

 function Mother(){ this.canSwim = function(){ console.log('yes'); } } function Son(){}; Son.prototype = new Mother; Son.prototype.canRun = function(){ console.log('yes'); } 

Now the son has one overridden method and one new

 function Grandson(){} Grandson.prototype = new Son; Grandson.prototype.canPlayPiano = function(){ console.log('yes'); }; Grandson.prototype.canSwim = function(){ console.log('no'); } 

The grandson now has two overridden methods and one new

 var g = new Grandson; g.canRun(); // => yes g.canPlayPiano(); // => yes g.canSwim(); // => no 
+8
May 5 '13 at 12:51
source share

Why not use objects instead of functions:

 var Base = { superalert : function() { alert('tst'); } }; var Child = Object.create(Base); Child.width = 20; Child.height = 15; Child.a = ['s','']; Child.childAlert = function () { alert(this.a.length); alert(this.height); } var Child1 = Object.create(Child); Child1.depth = 'depth'; Child1.height = 'h'; Child1.alert = function () { alert(this.height); alert(this.a.length); this.childAlert(); this.superalert(); }; 

And name it as follows:

 var child1 = Object.create(Child1); child1.alert(); 

This approach is much cleaner than functions. I found this blog explaining why inheritance with functions is not the right way to do this in JS: http://davidwalsh.name/javascript-objects-deconstruction

EDIT

var A child can also be written as:

 var Child = Object.create(Base, { width : {value : 20}, height : {value : 15, writable: true}, a : {value : ['s', ''], writable: true}, childAlert : {value : function () { alert(this.a.length); alert(this.height); }} }); 
+3
Jun 28 '13 at 11:26
source share
 //This is an example of how to override a method, while preserving access to the original. //The pattern used is actually quite simple using JavaScripts ability to define closures: this.somefunction = this.someFunction.override(function(args){ var result = this.inherited(args); result += this.doSomethingElse(); return result; }); //It is accomplished through this piece of code (courtesy of Poul Krogh): /*************************************************************** function.override overrides a defined method with a new one, while preserving the old method. The old method is only accessible from the new one. Use this.inherited() to access the old method. ***************************************************************/ Function.prototype.override = function(func) { var remember = this; var f = function() { var save = this.inherited; this.inherited = remember; var result = func.apply(this, Array.prototype.slice.call(arguments)); this.inherited = save; return result; }; return f; } 
+2
Jun 27 '13 at 19:05
source share

Here is my solution based on the standard prototype inheritance method described in.

First, I start by defining these helper methods that make it easier to read and read later:

 Function.prototype.setSuperclass = function(target) { // Set a custom field for keeping track of the object 'superclass'. this._superclass = target; // Set the internal [[Prototype]] of instances of this object to a new object // which inherits from the superclass prototype. this.prototype = Object.create(this._superclass.prototype); // Correct the constructor attribute of this class prototype this.prototype.constructor = this; }; Function.prototype.getSuperclass = function(target) { // Easy way of finding out what a class inherits from return this._superclass; }; Function.prototype.callSuper = function(target, methodName, args) { // If methodName is ommitted, call the constructor. if (arguments.length < 3) { return this.callSuperConstructor(arguments[0], arguments[1]); } // `args` is an empty array by default. if (args === undefined || args === null) args = []; var superclass = this.getSuperclass(); if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found."); var method = superclass.prototype[methodName]; if (typeof method != "function") throw new TypeError("TypeError: Object " + superclass.prototype + " has no method '" + methodName + "'"); return method.apply(target, args); }; Function.prototype.callSuperConstructor = function(target, args) { if (args === undefined || args === null) args = []; var superclass = this.getSuperclass(); if (superclass === undefined) throw new TypeError("A superclass for " + this + " could not be found."); return superclass.apply(target, args); }; 

Now, not only can you set the class superclass with SubClass.setSuperclass(ParentClass) , but you can also call overridden methods with SubClass.callSuper(this, 'functionName', [argument1, argument2...]) :

 /** * Transform base class */ function Transform() { this.type = "2d"; } Transform.prototype.toString = function() { return "Transform"; } /** * Translation class. */ function Translation(x, y) { // Parent constructor Translation.callSuper(this, arguments); // Public properties this.x = x; this.y = y; } // Inheritance Translation.setSuperclass(Transform); // Override Translation.prototype.toString = function() { return Translation.callSuper(this, 'toString', arguments) + this.type + " Translation " + this.x + ":" + this.y; } /** * Rotation class. */ function Rotation(angle) { // Parent constructor Rotation.callSuper(this, arguments); // Public properties this.angle = angle; } // Inheritance Rotation.setSuperclass(Transform); // Override Rotation.prototype.toString = function() { return Rotation.callSuper(this, 'toString', arguments) + this.type + " Rotation " + this.angle; } // Tests translation = new Translation(10, 15); console.log(translation instanceof Transform); // true console.log(translation instanceof Translation); // true console.log(translation instanceof Rotation); // false console.log(translation.toString()) // Transform2d Translation 10:15 

True, even with auxiliary functions, the syntax here is rather inconvenient. Fortunately, although syntax sugar (the most minimal classes ) was added in ECMAScript 6 to make things a lot prettier. For example:.

 /** * Transform base class */ class Transform { constructor() { this.type = "2d"; } toString() { return "Transform"; } } /** * Translation class. */ class Translation extends Transform { constructor(x, y) { super(); // Parent constructor // Public properties this.x = x; this.y = y; } toString() { return super(...arguments) + this.type + " Translation " + this.x + ":" + this.y; } } /** * Rotation class. */ class Rotation extends Transform { constructor(angle) { // Parent constructor super(...arguments); // Public properties this.angle = angle; } toString() { return super(...arguments) + this.type + " Rotation " + this.angle; } } // Tests translation = new Translation(10, 15); console.log(translation instanceof Transform); // true console.log(translation instanceof Translation); // true console.log(translation instanceof Rotation); // false console.log(translation.toString()) // Transform2d Translation 10:15 

Please note that ECMAScript 6 is still at the project stage, and as far as I know, it is not implemented in any major web browser. However, if you want, you can use something like the Traceur compiler to compile ECMAScript 6 down to the plain old ECMAScript 5 based on JavaScript. You can see the above example compiled using Traceur here .

+2
Dec 15 '13 at 18:10
source share

Although I agree with all of the above answers, I believe that JavaScript does not have to be object oriented (avoid inheritance), instead an object oriented approach should be sufficient in most cases.

I like the way. Eloquent JavaScript launches Chapter 8 on object-oriented programming, talking about OO. Instead of deciphering the best way to implement Inheritance, more energy should be devoted to studying the functional aspects of JavaScript, so I found Chapter 6 on functional programming, more interesting.

+1
Jun 18 '13 at 16:02
source share

How about this simple approach

  function Body(){ this.Eyes = 2; this.Arms = 2; this.Legs = 2; this.Heart = 1; this.Walk = function(){alert(this.FirstName + ' Is Walking')}; } function BasePerson() { var BaseBody = new Body(this); BaseBody.FirstName = ''; BaseBody.LastName = ''; BaseBody.Email = ''; BaseBody.IntroduceSelf = function () { alert('Hello my name is ' + this.FirstName + ' ' + this.LastName); }; return BaseBody; } function Person(FirstName,LastName) { var PersonBuild = new BasePerson(); PersonBuild.FirstName = FirstName; PersonBuild.LastName = LastName; return PersonBuild; } var Person1 = new Person('Code', 'Master'); Person1.IntroduceSelf(); Person1.Walk(); 
+1
Dec 12 '13 at 7:33
source share
 // // try this one: // // function ParentConstructor() {} // function ChildConstructor() {} // // var // SubClass = ChildConstructor.xtendz( ParentConstructor ); // Function.prototype.xtendz = function ( SuperCtorFn ) { return ( function( Super, _slice ) { // 'freeze' host fn var baseFn = this, SubClassCtorFn; // define child ctor SubClassCtorFn = function ( /* child_ctor_parameters..., parent_ctor_parameters[] */ ) { // execute parent ctor fn on host object // pass it last ( array ) argument as parameters Super.apply( this, _slice.call( arguments, -1 )[0] ); // execute child ctor fn on host object // pass remaining arguments as parameters baseFn.apply( this, _slice.call( arguments, 0, -1 ) ); }; // establish proper prototype inheritance // 'inherit' methods SubClassCtorFn.prototype = new Super; // (re)establish child ctor ( instead of Super ctor ) SubClassCtorFn.prototype.constructor = SubClassCtorFn; // return built ctor return SubClassCtorFn; } ).call( this, SuperCtorFn, Array.prototype.slice ); }; // declare parent ctor function Sup( x1, x2 ) { this.parent_property_1 = x1; this.parent_property_2 = x2; } // define some methods on parent Sup.prototype.hello = function(){ alert(' ~ hellothere ~ '); }; // declare child ctor function Sub( x1, x2 ) { this.child_property_1 = x1; this.child_property_2 = x2; } var SubClass = Sub.xtendz(Sup), // get 'child class' ctor obj; // reserve last array argument for parent ctor obj = new SubClass( 97, 98, [99, 100] ); obj.hello(); console.log( obj ); console.log('obj instanceof SubClass -> ', obj instanceof SubClass ); console.log('obj.constructor === SubClass -> ', obj.constructor === SubClass ); console.log('obj instanceof Sup -> ', obj instanceof Sup ); console.log('obj instanceof Object -> ', obj instanceof Object ); // // Object {parent_property_1: 99, parent_property_2: 100, child_property_1: 97, child_property_2: 98} // obj instanceof SubClass -> true // obj.constructor === SubClass -> true // obj instanceof Sup -> true // obj instanceof Object -> true // 
0
Aug 05
source share

The easiest way to use the AWeb library . Official sample:

  /** * A-class */ var ClassA = AWeb.class({ public : { /** * A-class constructor */ constructor : function() { /* Private variable */ this.variable1 = "A"; this.calls = 0; }, /** * Function returns information about the object */ getInfo : function() { this.incCalls(); return "name=" + this.variable1 + ", calls=" + this.calls; } }, private : { /** * Private function */ incCalls : function() { this.calls++; } } }); /** * B-class */ var ClassB = AWeb.class({ extends : ClassA, public : { /** * B-class constructor */ constructor : function() { this.super(); /* Private variable */ this.variable1 = "B"; }, /** * Function returns extended information about the object */ getLongInfo : function() { return this.incCalls !== undefined ? "incCalls exists" : "incCalls undefined"; } } }); /** * Main project function */ function main() { var a = new ClassA(), b = new ClassB(); alert( "a.getInfo " + (a.getInfo ? "exists" : "undefined") + "\n" + "a.getLongInfo " + (a.getLongInfo ? "exists" : "undefined") + "\n" + "b.getInfo " + (b.getInfo ? "exists" : "undefined") + "\n" + "b.getLongInfo " + (b.getLongInfo ? "exists" : "undefined") + "\n" + "b.getInfo()=" + b.getInfo() + "\n" + "b.getLongInfo()=" + b.getLongInfo() ); } 
-one
Aug 29 '13 at 15:20
source share

I found the solution much easier than extending and prototyping things. Actually, I don’t know how effective it is, but it looks clean and functional.

 var A = function (p) { if (p == null) p = this; p.a1 = 0; this.a2 = 0; var a3 = 0; }; var B = function (p) { if (p == null) p = this; p.b1 = new A(this); this.b2 = new A(this); var b3 = new A(this); this b4 = new A(); }; var a = new A (); var b = new B (); 

result:

 a a1 0 a2 0 b a1 0 b1 a2 0 b2 a2 0 b4 a1 0 a2 0 

practical example:

 var Point = function (p) { if (p == null) p = this; var x = 0; var y = 0; p.getPoint = function () { return [x,y]; }; p.setPoint = function (_x,_y) { x = _x; y = _y; }; }; var Dimension = function (p) { if (p == null) p = this; var w = 0; var h = 0; p.getDimension = function() { return [w,h] }; p.setDimension = function(_w,_h) { w = _w; h = _h }; }; var Rect = function (p) { if (p == null) p = this; var dimension = new Dimension(this); var location = new Point(this); }; var rect = new Rect (); rect.setDimension({w:30,h:40}); rect.setPoint({x:50,y:50}); 
-one
02 Sep '13 at 10:21 on
source share



All Articles