Accesssing ES6 class constructor function

James Treworgy jamietre at gmail.com
Fri Jan 6 12:11:16 UTC 2017


T.J. Thanks for the very thoughtful analysis. But I keep coming back to
this:

> since we
> wouldn't want `call`/`apply` to allow violating the "no `this` before
> `super(...)`" rule by setting the `this` binding early.

Why?

To me the best solution is also the simplest - just let people do this. Not
only does it avoid all the implementation complexity, but it also provides
feature parity between ES6 classes and conventional prototype constructor
functions.

Having some mechanism (e.g. via Reflect) would be better than nothing, but
it would also mean you have to write two versions of anything to support
both ways of creating prototypes.

It seems like there should be a very compelling reason to prevent someone
from using a feature. The risk of accidental "new" doesn't really apply to
`call` and `apply` -- and even in the direct invocation situation I don't
think it's compelling either (since we've had that since day 1 and managed
to get by :) but I don't really care if that's prevented.


On Fri, Jan 6, 2017 at 5:31 AM, T.J. Crowder <
tj.crowder at farsightsoftware.com> wrote:

> On Thu, Jan 5, 2017 at 7:21 PM, James Treworgy <jamietre at gmail.com> wrote:
>
> > > Can you clarify what prevents it from being made to work?
> >
> > The fundamental feature difference (continuing to think about this!) is
> that
> > with ES5 constructors, I can create an instance of something from an
> abitrary
> > constructor provided to me, and inject properties that will be available
> to
> > it *at contruction time.*
>
> and
>
> On Fri, Jan 6, 2017 at 3:49 AM, Don Griffin <don at sencha.com> wrote:
>
> > ...the issue James mentioned with DI and I've hit with
> multiple-inheritance are
> > the restriction on ".call()" and ".apply()" being used on constructor
> functions.
>
> Thinking out loud:
>
> Both James' DI case and the multiple-inheritance case could be
> addressed with a Reflect utility function that allows you to provide a
> hook triggered when `this` is being allocated for the base
> constructor. This is basically `call` for constructors, but with a
> hook rather than a *thisArg*. Just to have a name/concept for it:
> `Reflect.new(targetConstructor, hook, ...args)`. For now let's assume
> hook is a simple function that receives the freshly-allocated `this`
> and can either augment it or return a replacement, but I'll circle
> back to that later.
>
> James' example:
>
> ```js
> let o = Reflect.new(Ctor, thisObj => {
>     thisObj.logger = new Logger();
> });
> ```
>
> Let's assume `Ctor` extends `Base`; it would work like this:
>
> 1. Call [EvaluateNew(`Ctor`, `args`, `hook`)][1], note the new third
> argument. EvaluateNew passes the hook to Construct, which passes it to
> [[Construct]].
> 2. Eventually during that [[Construct]], `Ctor` calls `super`, which
> calls `Base`'s [[Construct]], also passing in the hook. (I don't know
> yet how [`super(...)`][4] has access to the hook; I guess we'd have to
> have it on the environment, like [[NewTarget]].)
> 3. We reach [Step 5][2] of `Base`'s [[Construct]] call. Since `Base`'s
> *kind* is "base", we perform OrdinaryCreateFromConstructor, but then
> pass the result through the hook. Since this particular hook doesn't
> return an object, *thisArgument* is set to the result from
> OrdinaryCreateFromConstructor as usual.
> 4. Construction completes as normal.
>
> So even the base constructor sees James' `logger` property on `this`
> by the time it has a `this`, because the hook gets a chance to augment
> it before the base constructor code runs.
>
> An MI example with `A`, `B`, and `C`, assuming they're all base
> constructors:
>
> ```js
> let o = Reflect.new(C, () =>
>     Reflect.new(B, () =>
>         new A()
>     )
> );
> // (Presumably do some mixing in of prototype properties...)
> ```
>
> Execution is like before, but in this case when we reach Step 5 of
> [[Construct]] for `B` and `C`, our hook returns an object, and so
> *thisArgument* is set to that object rather than the one from
> OrdinaryCreateFromConstructor.
>
> I said I'd circle back on hook being a simple function: The MI example
> above creates and throws away two objects it doesn't need to (the ones
> created for `B` and `C` but then replaced by the hook). If that's a
> concern, we can make hook an object with `allocate` and/or
> `postAllocate` properties: `allocate` would provide `this` (MI),
> `postAllocate` would just augment it (James' DI example). Or whatever.
> That's jumping forward to design; we're still at the concept stage and
> may well never reach design.
>
> If needed for things like `Error`, constructors could have a flag
> indicating that they cannot accept the hook (or at least, cannot
> accept the hook providing a different `this`), causing a throw at Step
> 5 of [[Construct]].
>
> Conceptually simple. Not necessarily simple in terms of impacts on
> specification or implementations. In terms of the spec, we have at
> least:
>
> * Adding `Reflect.new` (or whatever it's called)
> * Modifying EvaluateNew ([here][1])
> * Modifying Construct ([here][3])
> * Modifying [[Construct]] ([here][2])
> * Keeping track of the hook somewhere such that evaluating
> `super(...)` ([here][4]) can pass Construct the hook, possibly another
> slot on environment records
> * Possibly a flag slot or similar on functions like `Error`, if needed
>
> I'm not competent to speak to impacts on implementations.
>
> Which all sounds like a lot, but (modulo implementation complexity) I
> don't think it really is, and I think it's basically what we'd need to
> do to make `call`/`apply` work with constructors anyway (just passing
> around a hook function/object rather than a *thisArg*), since we
> wouldn't want `call`/`apply` to allow violating the "no `this` before
> `super(...)`" rule by setting the `this` binding early.
>
> -- T.J.
>
>
>   [1]: http://www.ecma-international.org/ecma-262/7.0/index.html#
> sec-evaluatenew
>   [2]: http://www.ecma-international.org/ecma-262/7.0/index.html#
> sec-ecmascript-function-objects-construct-argumentslist-newtarget
>   [3]: http://www.ecma-international.org/ecma-262/7.0/index.html#
> sec-construct
>   [4]: http://www.ecma-international.org/ecma-262/7.0/index.html#
> sec-super-keyword-runtime-semantics-evaluation
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170106/3999e7dd/attachment.html>


More information about the es-discuss mailing list