> I'm trying to provide a path where common code can migrate to ES6 classes
> before all the consumers have. So I was really looking for something that
> didn't require the subclasses to be touched at all (I wasn't clear about
> this).
I hope it was clear that newless supports this (functions, classes, and other
newless constructors can all inherit from newless constructors and vice versa).
Obviously there is the caveat noted in the README about dealing with `this`. In
newless, it’s mostly a non-issue unless the *super* class needs to keep a
reference to the actual instance that was created.
You simply can’t get around the fact that calling an ES6 class constructor will
create a new object instance, even if you already have one with the right
prototype chain (Even when using `Reflect.construct()`, which you really can’t
depend on in practice). Newless tries to work around this by setting the
prototype of the instance you already had (i.e. the one a function constructor
called `SuperConstructor.call(this)` with) to the object that was created when
instantiating the underlying class constructor. This preserves all the instance
properties, but means that the `this` in the superclass’s constructor is not
the exact same object as the `this` in the subclass’s constructor. (It also
*returns* the `this` from the superclass’s constructor, so a knowledgable
inheriting function can work with that instead and be totally safe with no
caveats.)
> I have a fair amount of control over how the inheritance is setup and how the
> ES6 class is written but that is about it.
However! If you are in control of the the class hierarchy from your class down
to the root, you can do a little better than newless can if you are willing to
get a little tricky:
```
class FunctionInheritable {
constructor() {
return this._constructor.apply(this, arguments);
}
_constructor() {}
static call(context, ...args) {
return this.apply(context, args);
}
static apply(context, args) {
return this.prototype._constructor.apply(context, args) || context;
}
}
class YourActualLibraryClass extends FunctionInheritable {
// all your inheritable classes will have to use `_constructor` instead of
`constructor`
_constructor(firstArg) {
// do whatever you want, there are no special requirements on what’s in here
this.something = firstArg;
global.libraryInstance = this;
}
someLibraryClassFunction() {
return this.something;
}
}
// any ES5 or earlier function-style “class” can now inherit with no changes
function SomeEs5FunctionConstructor() {
this.somethingElse = 'whatever';
YourActualLibraryClass.call(this, 'something');
}
SomeEs5FunctionConstructor.prototype =
Object.create(YourActualLibraryClass.prototype);
```
But, bottom line, you’re going to have to do something funky if you want to
upgrade function-style classes in the middle of an inheritance chain to ES6
classes without imposing any changes on the ultimate subclasses at the end of
the chain. ES6 simply goes out of its way to make it impossible to do that
without some hackery, be it some code like the above, a tool like newless, or a
transpiler (that does not fully enforce ES6 restrictions).
As a *library* author, I’ve run into the same issues you have here—with rare
exception, it’s still much too early to impose ES6-only support on a library’s
users. It’s why libraries I work on generally haven’t moved to ES6 classes
unless they’re doing something special as noted above.
Hope that helps,
Rob
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss