Code example:
ClassA.js
var classB = require('./ClassB');
function ClassA() {
this.ID = undefined;
this.Type = undefined;
....
}
ClassA.prototype.init = function init(id){
this.ID = id;
this.get();
if (this.Type === 'C' && Object.getPrototypeOf(this) === ClassA.prototype) {
return new classB().init(this.ID);
}
}
ClassB.js
function ClassB() {
ClassA.call(this);
this.additionalProp = undefined;
}
ClassB.prototype = Object.create(ClassA.prototype);
ClassB.prototype.constructor = ClassB;
I have implemented two classes ClassA and ClassB. ClassB is a child of CLassA and has some additional properties.
The prototype chain for ClassB is setup like this:
B.prototype = Object.create(A.prototype); B.prototype.constructor = B;
The information for the objects is retrieved from an API via an ID. At the time of the API call I do not know if the object needs to be an instance of ClassA or ClassB. So I always start with an object of ClassA to call the API. When the API returns a specific Type I want to convert my object from ClassA to more specific ClassB.
I tried to call the constructor of ClassB out of ClassA - this throws an error:
Uncaught TypeError: Object prototype may only be an Object or null: undefined
I don't think I should reference ClassB in ClassA at all, but it was worth a try...
Thank you for helping out a novice! :)
In a comment you've mentioned this error:
You get that because
ClassA.jsandClassB.jshave a circular relationship: each tries to import something the other exports. That can be fine in some cases, but here you have code inClassB.jstrying to useClassA.prototypein top-level code, andClassA.jsimportingClassBfromClassB.js. You end up with a placeholder for theClassAimport and theObject.create(ClassA.prototype)call doesn't work.It's going to be much easier if you define both of them in the same file, thanks to function declaration hoisting.
I'd also modify
initso that it always returns the instance, since you need to return a new object sometimes but not other times. So have it always return the instance simplifies the calling code.Here's a minimal-changes example:
Then using it (just for example):
That said, I think I'd refactor this. You've said that there's a separate
initmethod because sometimes you want to use methods on the objects before you have anid. That makes me thinkClassA(at least) is trying to do too much, both things that it can do when it doesn't know what it is (noid) and things it can do when it does. The instance returned by a constructor should be fully baked and ready to go. So probably better to split the parts ofClassAthat don't need anidoff into something else. That would also mean thatClassAdidn't have to refer toClassB, which isn't best practice.I think I'd probably also split
getoff to be separate from the classes, and have it return the appropriate instance.For example:
ClassA.js:ClassB.js:get.js(or whatever):That provides a much better separation of concerns.