Test for [[Construct]] invocation (was: Re: Must built-in prototypes also be valid instances? (Was: Why DataView.prototype object's [[Class]] is "Object"?))

Herby Vojčík herby at mailbox.sk
Tue Oct 2 12:32:19 PDT 2012



Allen Wirfs-Brock wrote:
> On Oct 2, 2012, at 10:52 AM, Herby Vojčík wrote:
>
>>
>> Allen Wirfs-Brock wrote:
>>> If you really need to strongly tie instantiation with branding you
>>> probably have to use a factory function:
>>>
>>> module Fooishness {
>>>     export function FooFactory ( ){return  new Foo};
>>>     FooFactory.isFoo = function (obj) {return !!obj. at FooBrand};
>>>
>>>     private @FooBrand;
>>>     class Foo {
>>>        constructor() {
>>>             /* establish the internal Fooness of the instance */
>>>             this. at FooBrand = true;
>>>        }
>>>     }
>>> }
>> var iWillBeFoo = {};
>> Fooishness.FooFactory().constructor(iWillBeFoo);
(here I missed `.call`)
>>
>> In fact, it has its logic to `newFoo. at FooBrand = true;` in factory, which solves it, hopefully cleanly enough.
>>
>>> Allen
>> Herby
>>
>
> Good catch, I forgot that the constructor is still exposed as a property on the instance.   The other way to prevent the constructor from being used to brand a pre-existing object is force an instantiation inside the constructor:
>
> private @FooBrand;
> class Foo {
>    constructor() {
>         let newFoo = Object.create(Foo.prototype);
>         /* establish the internal Fooness of the instance */
>         newFoo. at FooBrand = true;
>         return newFoo;
>    }
> }
> Foo.isFoo = function (obj) {return Reflect.hasOwn(obj, at FooBrand)&&  !!obj. at FooBrand};
>
> But this prevents Foo branding of subclasses of Foo. There is a
> tension here that I don't think is necessarily resolvable. To me, it
>  is another example why such class branding should only be used in
> specific high integrity situations and not as a general practice for
> all classes.

Well, here (and in other cases, too) it would be handy to be able to 
distinguish whether the call is constructor (new operator, super() call 
in class constructor) or plain call (the rest). It can be 
`arguments.isConstruct`, for example.

Than, it would simply be solved by `if (!arguments.isConstruct) return;` 
(or throw) as the first line in constructor.

> Allen

Herby

P.S.: Alternatively, this line can be intrinsic property of class 
constructor, but this makes class special and not a desugaring any more...


More information about the es-discuss mailing list