I'm having some trouble wrapping my head around inheritance in ES6 classes. Searching here, most of the answers are 10+ years old so I don't think they apply still. Let's start with the sample code:
class BaseClass {
baseUnitializedProp;
baseInitializedProp = 'abc';
constructor(properties) {
Object.assign(this, properties);
console.log('--- BaseClass Constructor ---');
console.log(this);
return this;
}
}
class ClassWithProp extends BaseClass {
childUnitializedProp;
childInitializedProp = 1;
}
class ClassWithOwnAssign extends ClassWithProp {
constructor(properties) {
const instance = super();
Object.assign(this, properties);
return instance;
}
}
const initedObj = new ClassWithProp({
childInitializedProp: 20,
childUnitializedProp: 10,
baseUnitializedProp: 15
});
console.log('--- Post initialization ---');
console.log(initedObj);
const assignedObj = new ClassWithOwnAssign({
childInitializedProp: 20,
childUnitializedProp: 10,
baseUnitializedProp: 15
});
console.log('--- Post initialization ---');
console.log(assignedObj);
My question is, why don't the child properties assignment propagate? From the console.log
inside the constructor you see that the properties were assigned, but outside the same properties end up with the declared initial value (or undefined).
The order of execution
super()
if any to work with this
this
)this
)super()
(if any)In your first case the properties that you pass are gone into the base class constructor and assigned to this
, but then overridden by the declared properties in the child class.
In your second case you don't pass any properties to the base constructor so it shows only declared initialized base class properties, than you assign all properties in the child constructor.
In this design pattern you can control the assignment precisely: in each constructor you can assign only props that belongs to the constructor's class. Any non declared in the classes props are skipped. I liked this one (made it right now):
class BaseClass {
#props = new Set;
baseUnitializedProp;
baseInitializedProp = 'abc';
constructor(properties) {
console.log('--- BaseClass Init ---');
console.log(this);
this.init(properties);
console.log('--- BaseClass Constructor ---');
console.log(this);
}
init(properties){
for(const k of Object.getOwnPropertyNames(this)){
if(k in properties && !this.#props.has(k)){
this[k] = properties[k];
this.#props.add(k);
}
}
}
}
class ClassWithProp extends BaseClass {
childUnitializedProp;
childInitializedProp = 1;
constructor(properties){
console.log('--- ClassWithProp Constructor called ---');
super(properties);
console.log('--- ClassWithProp Init ---');
console.log(this);
this.init(properties);
console.log('--- ClassWithProp Constructor after super() ---');
console.log(this);
}
}
const initedObj = new ClassWithProp({
childInitializedProp: 20,
childUnitializedProp: 10,
baseUnitializedProp: 15,
iAmDummyPleaseSkipMe: 'skipped'
});
console.log('--- Post initialization ---');
console.log(initedObj);
.as-console-wrapper{max-height: 100% !important}