this
isn't allowed in child classes before parent constructor call (super
) because this
doesn't certainly exist before that (parent class can return another object instead of this
). This ES6 class restriction is enforced by the specification.
As the reference states,
If there is a constructor present in subclass, it needs to first call super() before using "this".
If it's known that this
is used inside the function only after parent constructor call, it can be safely used:
class Foo {
constructor(callback) {
this.doFoo = callback;
}
}
class Bar extends Foo {
constructor() {
super(() => {
this.doBar();
})
}
doBar() {}
}
new Bar().doFoo();
Otherwise this
should be referred only after parent constructor call:
class DeferredPromise extends Promise {
constructor() {
let resolve, reject;
super((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
this.resolve = resolve;
this.reject = reject;
}
}
This will cause a problem specific to Promise
and described in this answer, the suggested solution is:
DeferredPromise.prototype.constructor = Promise;
This means that DeferredPromise
instance needs to be stored to access resolve
and reject
methods, they won't be available in chained promises:
let deferred = new DeferredPromise();
let nonDeferred = deferred.catch(() => {});
// nonDeferred.reject === undefined
This is the case for composition over inheritance. Deferred pattern doesn't need promise class to be extended, doing that has no obvious benefits. An implementation can be as simple as:
class Deferred {
constructor() {
this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
}