Inheritance is a mechanism for code reuse. The concept is similar to inheritance in living things : a child 'inherits' the behaviour and the traits of its parent, and in object oriented programming : a child class 'inherits' the behaviour (methods) and the traits (attributes and proprties) of its parent class.
Class inheritance follows the following rules :
In Classing{js}
, inheritance is done using classing.Class.Extends
as in the following code :
var Child = classing.Class.Extends(/* Parent's Reference */)({ /* The Defintion of The Class */ });
Here's an example of a class named Rectangle inherting from a class named Shape:
var Shape = classing.Class({ protected : { height: null, width : null, }, public : { Height : { get : function() {return this.height;}, set : function(value) {this.height = value;} }, Width : { get : function() {return this.width;}, set : function(value) {this.width = value;} }, Area : function() { return "Not Implemented"; } } }); var Rectangle = classing.Class.Extends(Shape)({ public : { Area : function() { return this.width*this.height; } } });
Notice that the Rectangle class overrides the Area method to calculate the area of the rectangle instead of returning "Not Implemented".
According to the second rule of inheritance mentioned above, any object of the Rectangle class will be able to access any of the two protected inherited attributes height and width inside its proprties and methods (like in the overriden method Area). And the two public inherited proprties Height and Width can be accessed from within or outside the class from the object.
base
keyword gives you access to the parent object within the methods and proprties of the child. It's particulary helpful in two cases : the chaining of constructors, and method overriding.
In the chaining of constructors, as we know , when the constructor of the child is invoked, it automatically invokes the constructor of the parent, and if there is no default constructor for the parent, the system can't guess what constructor to be invoked instead and how to pass the arguments to it. So, in the case of no default constructor in the parent, the developer has to invoke the paren't constructor manually, and this is when base
comes in hand.
Using base
as a function in a constructor function of the child invokes the constructor of the parent class. Here's an example:
var Shape = classing.Class({ protected : { height: null, width : null, }, public : { Construct : Function.create(xTyped , [ types(Number,Number), function(a , b) { this.height = a; this.width = b; } ]), Height : { get : function() {return this.height;}, set : function(value) {this.height = value;} }, Width : { get : function() {return this.width;}, set : function(value) {this.width = value;} }, Area : function() { return "Not Implemented"; } } }); var Rectangle = classing.Class.Extends(Shape)({ public : { Construct : Function.create(xTyped, [ types(), function() { base(0,0); }, types(Number,Number), function(x,y) { base(x,y); } ]), Area : function() { return this.width*this.height; } } });
Here we changed in the Shape class and added a 2-arguments constructor and no default constructors, and in the constructors of the Rectangle class we invoked the Shape constructor using base
as a function and passed to it the desired arguments.
In the case of methods overriding, sometimes we just need to add functionality to the overriden method not change it completely. To do this we can invoke the parent implemetation of the method inside the overriding instance in the child using base.methodName()
and then add the new functionality we want. Here's an example:
var Person = classing.Class({ public : { Greet : function() { return "Hi"; } } }); var HotelResptionest = classing.Class.Extends(Person)({ public : { Greet : function() { return base.Greet() + ", Welcome to our hotel"; //returns "Hi, Welcome to our hotel" } } });
Final
is used for two purposes :
classing.Final
(or with the Final
global shortcut) like we do with wrapping static components with the function Static
. Here's an example:
var Person = classing.Class({ protected : { name : null, age : null, }, public : { Construct : Function.create(xTyped , [ types(String,Number), function(a , b) { this.name = a; this.age = b; } ]), getInfo : Final(function() {return "Name: " + this.name + ", Age: " + this.age;}) } });
Attempting to override a final method will throw an error.
var VIP = classing.Class.Extends(Person)({ public : { getInfo : function(){return "VIP";} //throws an error } });
To create final classes, classing.Final.Class
is used in the following manner:
//for a parent class var ClassName = classing.Final.Class({ /* Your defintion goes here */ }); //for a child class var ClassName = classing.Final.Class.Extends(someParent)({ /* Your defintion goes here */ })
Here's an example:
var Parent = classing.Class({ protected : { name: null, age : null, }, public : { Name : { get : function() {return this.name;}, set : function(value) {this.name = value;} }, Age : { get : function() {return this.age;}, set : function(value) {this.age = value} } } }); var InfertileChild = classing.Final.Class.Extends(Parent)({}); var ImpossibleChild = classing.Class.Extends(InfertileChild)({}) //throws an error