> 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

Reply via email to