Subclassing a class with required parameters in JavaScript - 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
};
}());

Related

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);

how to implement parasitic inheritance to avoid nesting

I would like to follow the inheritance structure shown above. I would like create an engineer using this syntax:
var Mark = new Employee(id).WorkerBee(project).Engineer();
To achieve this syntax, I have to create a nested object following a parasitic inheritance pattern like so:
function Employee(id) {
this.id = id;
this.WorkerBee = function(project) {
this.project = project;
this.Engineer = function() {
...
return this;
};
return this;
};
}
To avoid deep layers of nesting, I am trying to rewrite it using prototypes. How can I rewrite my code to achieve the same goal as above ?
function Employee(id) {
//variables
this.id = id
this.name = "";
this.dept = "general";
//methods
this.getId = function() {
return this.id
}
}
Employee.prototype.WorkerBee = WorkerBee;
function WorkerBee(project) {
//variables
this.projectName = project
this.projects = [];
//methods
this.getProjectName = function() {
return this.projectName
}
return this
}
WorkerBee.prototype.Engineer = Engineer
function Engineer() {
//variables
this.dept = "engineering";
this.machine = "";
//methods
this.getDept = function() {
return this.dept
}
return this
}
var Mark = new Employee("5").WorkerBee("Secret Project").Engineer();
console.log(Mark.getId()) //should print "5"
console.log(Mark.getProjectName()) //should print "Secret Project"
console.log(Mark.getDept()) //should print engineering
UPDATE:
Ok, I understand partially. What is the reason why you want to do this? Do you just want a shortcut for creating multiple instances using multiple statements?
Should the instance of C returned by A().B().C() be any different than the one created with the standard new C()?
If you just want to chain constructors, you can add the context in which they are defined (most likely the global object) to the prototype chain of the created entities. You should be able to do that:
var A = function () {};
A.prototype = Object.create(this);
What this does not eliminate though is the need for the new keyword for instantiation. You would need to do new (new (new A()).B()).C(). I can't think of a different approach than having a helper function which would create constructors which do not require the new keyword:
var define = function (init) {
var Constructor = function () {
if (!(this instanceof Constructor)) {
return new Constructor();
}
if (init) {
init.apply(this, Array.prototype.slice.call(arguments));
}
};
Constructor.prototype = Object.create(this);
return Constructor;
};
The usage is:
var A = define(function (x, y) {
this.x = x;
this.y = y;
});
var a1 = new A(1, 2);
// a1 instanceof A === true
// a1.x === 1
// a1.y === 2
var a2 = A(1, 2);
// a2 instanceof A === true
// a2.x === 1
// a2.y === 2
If you have the constructors A, B and C, you can use the following notations interchangeably:
var a = new A();
var b = new B();
var c = new C();
var a = A();
var b = B();
var c = C();
var b = A().B();
var c = A().C();
var a = B().C().A();
In case of A().B().C(), you do not have access to the instances of A and B.
Can you elaborate a bit more on what is your deal?
OLD ANSWER:
What you have there is madness as you basically merge three constructors and make it seem that `WorkerBee` and `Employee` are actually instantiated while they are not.
I'm not going to question the new A().B().C() notation even though I find it quite messed up.
You probably want to make use of the instanceof operator the following way.
var A = function (x) {
if (!(this instanceof A)) return new A(x);
this.x = x;
};
var B = function (y) {
if (!(this instanceof B)) return new B(y);
this.y = y;
};
var C = function () {
if (!(this instanceof C)) return new C();
};
A.prototype.B = B;
B.prototype.C = C;
You can now call new A() and A(), new B() and B() and new C() and C() interchangeably while achieving the same result as both of the calls always return an instance of the constructor.
new A() instanceof A === true
new A().B() instanceof B === true
new A().B().C() instanceof C === true
Based on the comments, you seem to have the belief that you have to use this odd, verbose mechanism in order to have inheritance between Employee <- WorkerBee <- Engineer (and such), but you don't; normal inheritance is all you need for this:
// ==== Employee
function Employee(id) {
this.id = id;
}
// Add Employee methods to Employee.prototype, e.g.:
Employee.prototype.getId = function() {
return this.id;
};
// ==== WorkerBee, derived from Employee
function WorkerBee(id, project) {
// Inheritance, part 1: Chain to the base constructor
Employee.call(this, id);
// WorkerBee stuff
this.project = project;
}
// Inheritance, part 2: Create the object to use for WorkerBee
// instance prototypes, using Employee.prototype as its prototype.
WorkerBee.prototype = Object.create(Employee.prototype);
WorkerBee.prototype.constructor = WorkerBee;
// Add WorkerBee methods to WorkerBee.prototype, e.g.:
WorkerBee.prototype.getProjectName = function() {
return this.project;
};
// ==== Engineer, derived from WorkerBee
function Engineer(id, project) {
// Inheritance, part 1: Chain to the base constructor
WorkerBee.call(this, id, project);
}
// Inheritance, part 2: Create the object to use for Engineer
// instance prototypes, using WorkerBee.prototype as its prototype.
Engineer.prototype = Object.create(WorkerBee.prototype);
Engineer.prototype.constructor = Engineer;
// Add Engineer methods to Engineer.prototype, e.g.:
Engineer.prototype.getDept = function() {
return "Engineering";
};
// ==== Usage
var mark = new Engineer("5", "Secret Project");
snippet.log(mark.getId()); // "5"
snippet.log(mark.getProjectName()); // "Secret Project"
snippet.log(mark.getDept()); // "Engineering"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
That's the standard way to do prototypical inheritance using constructor functions in JavaScript (for now; in ES6, you'd use the new class feature, which does basically the same thing, with some syntactic sugar). Just add Manager (derived from Employee) and SalesPerson (derived from WorkerBee).
On old browsers, you may need a partial polyfill for Object.create, which looks like this:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "The two-argument version of Object.create cannot be polyfilled.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor();
};
}
There are transpilers for taking ES6 source with class and turning it into ES5 code. There's also my Lineage script, which makes inheritance a lot less verbose.

JavaScript build a constructor of constructors

Here is a simple example of what I want :
var ConstBuilder = function() {
var constructor = function() {} ;
constructor.prototype = {} ;
return constructor ;
} ;
ConstBuilder.prototype = {
add : function(name, value) {
this.prototype[name] = value ;
}
} ;
var A = new ConstBuilder() ;
A.add('test', function() {
console.log('test') ;
}) ;
var a = new A() ;
a.test() ;
This code will fail as A is not an instance of ConstBuilder (because A comes from a returned var constructor = function() {} and won't have the methods defined in its prototype (add).
But this would be useful to modify the super constructor's prototype to have things like :
ConstBuilder.prototype.remove = function(name) {
delete this.prototype[name] ;
} ;
A.remove('test') ;
a.test ; // undefined
Is there a way to have a function as an instance of another ? So this function may implicitely "inherit" all the methods defined in its constructor's prototype.
Or if you have other suggestions, I aim to build modulable constructors - as instances with prototypes are.
Please make sure you have understood the difference between the .prototype property and the internal inheritance-prototype.
The code will fail as A is not an instance of ConstBuilder. Is there a way to have a function as an instance of another?
A is, as every constructor needs to be, a Function. So if you just define your add and remove methods on the Function.prototype, it will work:
Function.prototype.add = function(name, value) {
this.prototype[name] = value;
};
Function.prototype.remove = function(name) {
delete this.prototype[name];
};
function A() {}
A.add('test', function(){console.log('test');});
var a = new A();
a.test(); // test
A.remove('test');
a.test; // undefined
There is no possibility however to let a function inherit from something else than Function.prototype - see Can a JavaScript object have a prototype chain, but also be a function?. If you don't want to modify the native Function.prototype object, you still can use the mixin pattern:
var Constr = (function() {
function add(name, value) {
this.prototype[name] = value;
}
function remove(name) {
delete this.prototype[name];
}
return function mixin(c) {
c.add = add;
c.remove = remove;
return c;
};
})();
var A = Constr(function() {…});
A.add("test", …);
var a = new A();
a.test(); // test
I aim to build modulable constructors
You could use the builder pattern, as you just have seem to tried.
function ConstBuilder() {
this.prototype = {};
};
ConstBuilder.prototype = {
add: function(name, value) {
this.prototype[name] = value;
},
remove: function(name) {
delete this.prototype[name];
},
getConstructor: function() {
var constructor = function() {};
constructor.prototype = this.prototype;
this.prototype.constructor = constructor;
return constructor;
}
};
var A = new ConstBuilder().add('test', function() {
console.log('test');
}).getConstructor();
var a = new A();
a.test(); // test
To remove functions later, you would need to save a reference to the builder.
I think that you are looking for an example of how to do JavaScript's "prototypical inheritance". When JavaScript looks for a property on an object, it first checks the object itself. Next it checks the prototype. However, since everything in JavaScript is an object and the prototype is an object
function Root(){}
Root.prototype.fromRoot = function() { console.log("I'm on Root's prototype."); };
function Child(){}
Child.prototype = new Root();
Child.prototype.fromChild = function() { console.log("I'm on Child's prototype."); };
var r = new Root();
var c = new Child();
r.fromRoot(); // works
c.fromRoot(); // works
c.fromChild(); // works
r.fromChild(); // fails
function a (x,y,construct)
{
if (!construct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y,true) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
second way
function a (x,y)
{
if (arguments.callee.doNotConstruct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
a.doNotConstruct=true;
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
a.doNotConstruct=false;
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
put this in a function
function prototypeInheritance (inheritor,parent)
{
parent.doNotConstruct=true;
inheritor=new parent ();
inheritor.prototype.constructor=inheritor;
inheritor.parent=parent;
parent.doNotConstruct=false;
}
you can call the parent property with (arguments.callee.parent) in the inheritor constructor and you can check doNotConstruct with arguments.callee.doNotConstruct in the parent constructor

javascript's different extend methods

What is the difference between extend methods in JavaScript?
Let's say we have the following classes:
var BaseClass = function() {
this.class_name = 'BaseClass';
this.foo = function() {
return 'foo';
}
this.sub = {
moreStuff: 'weeee'
}
};
BaseClass.prototype.bar = function () {
return 'To be or not to be';
}
var SubClass = function() {
this.class_name = 'SubClass';
this.bar = function() {
return 'bar';
}
this.sub = {
moreStuff: 'wooohooo'
}
};
Method A:
SubClass.prototype = new BaseClass();
SubClass.prototype.constructor = SubClass;
Method B (from underscore.js):
_.extend = function(obj) {
each(slice.call(arguments, 1), function(source) {
if (source) {
for (var prop in source) {
obj[prop] = source[prop];
}
}
});
return obj;
};
Method C (from LiveScript):
function extend$(sub, sup){
function fun(){}
fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
Method A looks simpler. Why go through the trouble of copying the object, one property at a time?
Yes, Method A looks simpler but using it you can inherit only from one object. What if you want your SubClass to inherit from BaseClassOther as well. In this case you should go for the Method B ( to inherit from BaseClassOther as well).
You can not do
SubClass.prototype = new BaseClassOther();
again this will overwrite prototype property.
Please have a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
In Method A, in other circumstances, BaseClass() might be written to require an argument and to fail if it does not receive a valid one. The other two methods are not bothered by this. Perhaps the inherited constructors you are working with are not bothered by this either.

Nesting same type JavaScript-objects with property fallbacking?

I'm looking for a method to create nested js-objects of the same type with property-fallbacking.
I'd like to be able to write for instance:
state.isLoggedIn and if this object doesn't have this property (undefined) then it should look in a base-state etc until no base-states exists anymore, then return undefined.
With base-state I mean some other state that this state is based on, not inherited like is class inheritance.
I was thinking of making some kind of class like this:
function State(base) {
this.base = base; // also a state
}
When I try to get a property P from a state A that is based on another state B, and state A doesn't define a property P it should go look in state B instead.
I know I could use a function like state.getState(key) that looks in its own properties first and then in the base-properties. But I'm looking for a method of doing this with normal properties instead.
In C# it would look something like this (and making it a dynamic object I would get almost excatly the same ducked typed state I'm looking for in javascript):
class State
{
public State(State base)
{
_base = base;
}
State _base;
Dictionary<string, object> _values = new Dictionary<string, object>();
public object this[string key]
{
get { return _values.ContainsKey(key) ? _values[key] : _base[key]; }
set { _values[key] = value; }
}
}
Any ideas? Possible?
UPDATE:
This is what I got now:
function State() {
}
function ViewModelBase() {
var self = this;
self.__parent = ko.observable(null);
self.state = new State();
self.parent = ko.computed({
read: function () {
return self.__parent();
},
write: function (value) {
if (getObjectClass(value) !== "ViewModelBase") throw new Error("Wrong type of parent.");
var p = self.__parent();
if (p != null) throw new Error("Allready parented.");
self.__parent(value);
// here i'd like to inherit/nest self.state with value.state
}
});
}
Not sure if this is what you're looking for, but maybe it is:
var state1 = {a : 1};
var state2 = Object.create(state1);
state2.b = 2;
console.log(state2.a); // 1
var state3 = Object.create(state2);
state3.a = 10; // creates an own "a" in state3
console.log(state1.a); // 1
console.log(state2.a); // 1
console.log(state3.b); // 2
This is using inheritance, as I suggested in my original comment to your question. Object.create returns a new object that uses the object passed as the first argument as its [[Prototype]] (which some implementations expose via the __proto__ property). When you try to access a property of the new object and an own property is not found, it looks up in the prototype chain.
Object.create is not supported by older browsers, but a very simple polyfill is available on MDN.
This is what CoffeeScript uses for class extenstions (using prototype inheritance):
var __hasProp = {}.hasOwnProperty,
__extends = function (child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key)) child[key] = parent[key];
}
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
This assumes that the class functions are all a part of the prototype of the class functions.
For example:
Animal = (function() {
function Animal() {}
Animal.prototype.name = 'Generic Animal';
Animal.prototype.my_sound = 'none';
Animal.prototype.sound = function() {
return console.log(this.my_sound);
};
return Animal;
})();
Cow = (function(_super) {
__extends(Cow, _super);
function Cow() {
return Cow.__super__.constructor.apply(this, arguments);
}
Cow.prototype.name = 'Cow';
Cow.prototype.my_sound = 'Moo';
return Cow;
})(Animal);
Cat = (function(_super) {
__extends(Cat, _super);
function Cat() {
return Cat.__super__.constructor.apply(this, arguments);
}
Cat.prototype.name = 'Cat';
Cat.prototype.my_sound = 'Meow';
return Cat;
})(Animal);

Categories