Javascript inheritance and function overriding - javascript

// Base state class -------------------------
function StateConstuctor()
{
}
// Inherited learn class --------------------
function StateLearnConstructor()
{
}
// Inherited exam class ---------------------
function StateExamConstructor()
{
}
function extend(Child, Parent)
{
var F = function() { }
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child
Child.superclass = Parent.prototype
}
function createState(rollType)
{
if (rollType == 'learn')
{
extend(StateLearnConstructor, StateConstuctor);
var state = new StateLearnConstructor();
return state;
}
else if (rollType == 'exam')
{
extend(StateExamConstructor, StateConstuctor);
var state = new StateExamConstructor();
return state;
}
}
StateConstuctor.prototype.getTitles = function()
{
console.log('base "virtual" function');
}
StateLearnConstructor.prototype.getTitles = function()
{
console.log('learn');
}
StateExamConstructor.prototype.getTitles = function()
{
console.log('exam');
}
Hello, I have the following "OOP" structure and I want to emulate something like virtual functions in C++. So I have base virtual function in StateConstructor and different realizations for each subclass.
var state = createState('exam');
state.getTitles();
But this code calls StateConstructor base virtual function. What's wrong here?

createState() is overwriting the prototypes for your StateLearnConstructor and your StateExamConstructor after you have assigned functions to them.
You shouldn't be conditionally extending them. Just extend them:
extend(StateLearnConstructor, StateConstuctor);
extend(StateExamConstructor, StateConstuctor);
StateConstuctor.prototype.getTitles = function () {
console.log('base "virtual" function');
};
StateLearnConstructor.prototype.getTitles = function () {
console.log('learn');
};
StateExamConstructor.prototype.getTitles = function () {
console.log('exam');
};
function createState(rollType) {
if (rollType == 'learn') {
return new StateLearnConstructor();
} else if (rollType == 'exam') {
return new StateExamConstructor();
}
}
Once you do that, your "virtual functions" should work as expected.
demo
Note: Your implementation for extend() is more complicated than it needs to be. The modern way to inherit a prototype is to use Object.create():
function extend(Child, Parent) {
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.superclass = Parent.prototype;
}

Related

class with static and instance methods

The goal - create function, that behaves like class with static methods and at the same time can be used to create instanses. All this resides in dedicated namespace. I am looking for "standard" ptototype approach. And is it good practice in general?
I tried to avoid use reference to "class" by function name. If I would have 10 or more static methods it could be difficult. In first example I used _self, and in another method defineProperties.
var MyNamespace = (function() {
function MyClass0(e) {
this.e = e;
var _self = MyClass0;
_self.prototype = {
instanceMethod: function() {
}
}
_self.staticMethod = function() {
}
if (!e) {
return _self;
}
}
function MyClass1(e) {
this.e = e;
MyClass1.prototype = {
instanceMethod: function() {
}
}
var properties = {
staticMethod: {
value: function() {
}
}
};
Object.defineProperties(MyClass1, properties)
if (!e) {
return MyClass1;
}
}
return {
MyClass0: MyClass0(), // use _self
MyClass1: MyClass1() // use defineProperties
}
})();

Javascript/Node.js: ES5 child class instance accessing parent class method

I am trying to access parent's method in child's constructor as following:
file1.js
var ParentClass = function(arg) {
this.arg = arg;
this.result = {};
};
ParentClass.prototype = {
constructor: ParentClass,
isActive: function(condition) {
return new Date(condition.valid).getTime() <= Date.now())
}
};
module.exports = ParentClass;
file2.js
var ParentClass = require('file1');
var ChildClass= function(arg) {
ParentClass.apply(this, arguments);
this.init();
};
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass;
ChildClass.prototype = {
init: function() {
this.result = this.arg.validity
.filter(function(elem) {
return this.isActive(elem)
}.bind(this));
}
}
module.exports = ChildClass;
file3.js
var ChildClass= require('file2.js');
var instance = new ChildClass(param);
initializing such instance gives me
TypeError: this.isActive is not a function
at Object.<anonymous> (file2.js)
at Array.filter (native)
at Object.ChildClass.init (file2.js)
Help and explanation appreciated. Thank you!
You have two separate assignments to ChildClass.prototype. One will override the other. Instead, you need to first initialize your prototype with Object.create() as you are doing and then you need to ADD new methods to it, not assign to the whole prototype, thus replacing everything you just put there.
These are the two conflicting statements:
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype = {...};
One common way to fix this is to use Object.assign() to copy your methods onto the existing prototype:
Object.assign(ChildClass.prototype, {
init: function() {
this.result = this.arg.validity
.filter(function(elem) {
return this.isActive(elem)
}.bind(this));
}
});
This will copy each of your methods over to the already existing prototype object and this method is more commonly used when you have lots of methods.
You can also just assign the new methods one at a time (more commonly used when you have just a few methods):
ChildClass.prototype.init = function() {
this.result = this.arg.validity.filter(function(elem) {
return this.isActive(elem)
}.bind(this));
}
You are redefining ChildClass.prototype as a new object, which overwrites your assignment using Object.create() a few lines prior. Instead, simply define the init method on it.
Try this:
var ParentClass = function(arg) {
this.arg = arg;
this.result = {};
};
ParentClass.prototype = {
constructor: ParentClass,
isActive: function(condition) {
return new Date(condition.valid).getTime() <= Date.now();
}
};
var ChildClass = function(arg) {
ParentClass.apply(this, arguments);
this.init();
};
ChildClass.prototype = Object.create(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass;
ChildClass.prototype.init = function() {
this.result = this.arg.validity
.filter(function(elem) {
return this.isActive(elem);
}.bind(this));
};
var instance = new ChildClass({
validity: [{
valid: "01/01/17"
}]
});
console.log(instance);

Simpler JavaScript inheritance without duplicate code

I am always struggling with the JavaScript object/class inheritance thing. I also don't like the duplicate code in all the examples I can find (the name of the object needs to be written a few times).
As far as I understand, proper inheritance in JavaScript looks like this:
function Parent(v) {
console.log('Parent', v);
}
Parent.prototype.helloParent = function() {
console.log('hello parent');
}
function Child(v) {
Parent.call( this, 'from child');
console.log('Child');
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.helloChild = function() {
console.log('hello child');
}
c = new Child();
console.log(c instanceof Child);
c.helloParent();
c.helloChild();
In this example, to extend the "Parent" object, I have to write "Child" four times, "Parent" two times. I want to type them both just once once – because of DRY.
I also don't want to define a custom function for this inheritance stuff. That just feels odd for me, to need a user function for such a fundamental functionality (and it is getting hard to read unknown code, because you never know what this specific inheritance function is doing exactly).
So I tried to find a simpler version. However I am not sure if I missed something?
function Parent(v) {
console.log('Parent', v);
this.helloParent = function() {
console.log('hello parent');
}
}
(Child = function(v) {
this.constructor('from child');
console.log('Child');
this.helloChild = function() {
console.log('hello child');
}
}).prototype = Parent.prototype;
c = new Child();
console.log(c instanceof Child);
c.helloParent();
c.helloChild();
Is this okay or does it have serious drawbacks?
Edit: Regarding the comments, sadly it seems that it has some serious drawback. Are there any other solutions to reduce at least to write the name of the parent object multiple times?
I use two very small functions for simplifying inheritance in JavaScript:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function extend(constructor, keys) {
var prototype = Object.create(constructor.prototype);
for (var key in keys) prototype[key] = keys[key];
return defclass(prototype);
}
It is used as follows:
var Parent = defclass({
constructor: function (a) {
console.log("Parent", a);
},
helloParent: function () {
console.log("helloParent");
}
});
var Child = extend(Parent, {
constructor: function () {
Parent.call(this, "fromChild");
console.log("Child");
},
helloChild: function () {
console.log("helloChild");
}
});
Finally:
var child = new Child;
console.log(child instanceof Child);
child.helloParent();
child.helloChild();
Putting it all together:
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
function extend(constructor, keys) {
var prototype = Object.create(constructor.prototype);
for (var key in keys) prototype[key] = keys[key];
return defclass(prototype);
}
var Parent = defclass({
constructor: function (a) {
console.log("Parent", a);
},
helloParent: function () {
console.log("helloParent");
}
});
var Child = extend(Parent, {
constructor: function () {
Parent.call(this, "fromChild");
console.log("Child");
},
helloChild: function () {
console.log("helloChild");
}
});
var child = new Child;
console.log(child instanceof Child);
child.helloParent();
child.helloChild();
Hope that helps.
oop in javascript is ugly. (at least until ES6 which supports the class and implements keywords) but even ES6 will not support multiple inheritance. I wrote a small class library (available on github) for javascript that makes creating classes and inheritance much easier to both develop and maintain. for example to create a class just do this:
ds.make.class({
type: 'a',
constructor: function (x) { this.val = x; },
mul: function (s) {
this.val *= s;
return this;
}
});
// now to inherit class a just do this...
ds.make.class({
type: 'b',
inherits: a,
constructor: function (x) { this.val = x; },
sub: function (s) {
this.val -= s;
return this;
}
});
var o = new b(5);
var output = o.mul(3).sub(5).val; // output = 10

Combining inheritance with the module pattern

I like the module pattern that returns constructors as described in:
http://elegantcode.com/2011/02/15/basic-javascript-part-10-the-module-pattern/
However I am not sure how to inherit from an object that is implemented with this pattern. Suppose I have a parent object implemented thus...
namespace('MINE');
MINE.parent = (function() {
// private funcs and vars here
// Public API - constructor
var Parent = function (coords) {
// ...do constructor stuff here
};
// Public API - prototype
Parent.prototype = {
constructor: Parent,
func1: function () { ... },
func2: function () { ... }
}
return Parent;
}());
How do I define a child object that also uses the module pattern that inherits from parent in such a way that I can selectively override, for example, func2?
MINE.child = (function () {
var Child = function (coords) {
Parent.call(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.func2 = function () { ... };
return Child;
}());
I find the solution from this blog (http://metaduck.com/08-module-pattern-inheritance.html) cleaner. For example:
function Parent(name) {
// Private variables here
var myName;
// Constructor
myName = name;
// Public interface
return {
func1: function () {alert("Parent func1. Name: " + myName); },
func2: function () {alert("Parent func2. Name: " + myName); }
}
}
function Child(name) {
// Private variables here
var myName,
exportObj;
// Constructor
// Inherit
exportObj = Parent(name + "'s father");
// Override
exportObj.func2 = function () {
alert("Child func2. Name: " + name);
}
// Export public interface
return exportObj;
}
An example can be run here: http://jsfiddle.net/wt4wcuLc/

Subclassing a class with required parameters in JavaScript

If subclassing a "class" in JavaScript is done like so:
var ParentClass = function() {
// something
};
var ChildClass = function() {
// something
};
ChildClass.prototype = new ParentClass();
... what should I do when the parent class has required parameters?
var ParentClass = function(requiredParameter) {
if (typeof requiredParameter === 'undefined') {
throw new TypeError("'requiredParameter' is required!");
}
};
var ChildClass = function() {
// something
};
ChildClass.prototype = new ParentClass();
// ^ Throws TypeError
Thanks.
This is how its done:
function Parent( a ) {
this.a = a;
}
function Child( a, b ) {
Parent.call( this, a ); // this is crucial
this.b = b;
}
Child.prototype = Object.create( Parent.prototype );
Child.prototype.constructor = Child;
Live demo: http://jsfiddle.net/ECCgt/ (analyze the instances in the console)
The way you're doing it
ChildClass.prototype = new ParentClass();
is a dirty hack which is broken and should be avoided. Use Object.create to set up the inheritance relationship between the two prototype objects.
The second line
Child.prototype.constructor = Child;
is somewhat optional. We are correcting the constructor property because we had to overwrite Child.prototype in order to set up the inheritance. If you don't care about the constructor property, just leave out that line.
Subclass it like this instead:
function clone (obj) {
if (!obj) return;
clone.prototype = obj;
return new clone();
}
var ParentClass = function() {
// something
};
var ChildClass = function() {
// something
};
ChildClass.prototype = clone(ParentClass.prototype);
ChildClass.prototype.constructor = ChildClass; // if you want
Now you don't have to worry about it, because you don't have to call the parent constructor to subclass it :)
A better way to inherit...
var inherit = (function () {
var F = function () {}; // cache function
return function (C, P) { // Accepts Constructor and Parent
F.prototype = P.prototype;
// faster prototype chain lookup than direct instantiation
C.prototype = new F();
C._super = P.prototype;
C.prototype.constructor = C; // for checking instanceof
};
}());

Categories