13.2.2 [[Construct]], constructor, and [[Class]] (was __proto__)

liorean liorean at gmail.com
Sun Sep 23 08:59:46 PDT 2007


> > On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
> > > What I've found is that it's always giving wrong constructor property
> > > with inheritance chains.
> > >
> > > A <-- B <-- C
> > > c = (new C).constructor;// A
> > >
>
> <snip> I meant an enumerable superclass property!

> On 9/22/07, liorean <liorean at gmail.com> wrote:
> > You get that if you do the following:
> >
> >     function A(){}
> >     function B(){}
> >     B.prototype=new A;
> >     function C(){}
> >     C.prototype=new B;
> >
> > Because if you do that, you replace the prototype containing the
> > original constructor property  (e.g. a reference back to the function
> > C) with an instance of another constructor (e.g. B), but that instance
> > doesn't have the constructor property that the original prototype had.
> > If you want to keep the constructor properties, you need to do that
> > manually. (With the obvious result that then the constructor property
> > will be enumerable. Which can be changed through adding a call on
> > propertyIsEnumerable in ES4.)

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
> Ah, sorry, I said a few things wrong!
>
> 1. constructor is DontEnum.13.2 - http://bclary.com/2004/11/07/#a-13.2
> (It's the user-defined superclass property that is enumerable.)

If I wasn't clear on that, the that's the difference between the one
that the implementation would set up for you and the one you'd have to
create manually to preserve the constructor chain in ES3. And ES4
allows for making it non-enumerable manually, so in ES4 code using the
prototypal inheritance model could be rid of this problem, albeit with
a slight cludgyness added to the code because developers actually have
to both add the property to an instance and set it to be
non-enumerable.

> 1. The constructor property should be on the object instance *created*
> by the function.

That argument I agree with. It should be on the instance and not the prototype.




> > On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
> > > How about a constructor property on the function instance?

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
> 2. (new function(){}).constructor should be Function.

I agree. And in ES3 it is, unless the function either:
- Returns another object than that it was passed from [[Construct]]
- Creates a constructor property on the this object that is not a function
- Has it's prototype overwritten


A disagreement of terminology I think. If you ask me, a function
instance is a function object. When using a function instance as a
constructor, you create an instance of that constructor (== function
instance) which is a plain, ordinary, mundane, normal,
run-of-the-mill, typical object. (Agh, ran out of synonyms!)




> On 9/22/07, liorean <liorean at gmail.com> wrote:
> > Which could be done, of course, it should be a simple thing to add
> > that in the algorithm for [[Construct]]. But then we have the question
> > of what to do with constructors that return other objects than that
> > set up by steps 1 through 5 of the [[Construct]] algorithm. A
> > constructor can return other objects, you know.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
> In ES4, it is a syntax error to specify a result type of a
> constructor. If someone is using new F, the constructor property of
> the instance should be F.

If it's a constructor in the ES4 introduced classical inheritance
sense, I have no arguments against that. And neither do I have any
strong arguments against it for type annoted functions. The rather
weak argument I do have against the latter is that it makes it harder
to simply add type annotations to old type consistent ES3 code and
have it work.
But for ES3 and real web compatibility, I don't think changing the
algorithm to not allow ordinary ES3 functions used as constructors to
return objects other than the one set up by [[Construct]] will work.

Take a look at this article for example:
<uri:http://www.digital-web.com/articles/objectifying_javascript/>
It's only one of many articles, tutorials and scripting tips and
tricks I've seen that uses the new keyword that way.

I've actually seen developers arguing that it's a proper way of using
the new keyword since the new keyword makes it clear you're
constructing an object up front instead of using regular function
calls that only make it obvious after you've read the function body.
Typical example is the argument that "new function(...){...}(...)"
makes it's usage as setting up an object more clear than
"(function(...){...}(...))" or "(function(...){...})(...)".

It's not an argument I generally agree with, but I see it around, and
my impression is that it's getting more common. A few years ago I saw
it only once or twice. Mostly, I think this trend is due to far larger
amounts of advanced scripting being done, and as an effect more
interest in using OO constructs.




> (new F).constructor; // should be F.
>
> The constructor property should match the [[Construct]] property. This
> should happen right before the prototype.

I agree, it should. Before or after is not important. It would
override the one in the prototype chain in any case, since that's the
order property lookup will use.




 > On 9/22/07, liorean <liorean at gmail.com> wrote:
> > probably wouldn't hurt much code out there.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
> What could it hurt? What would get broken?

Any code that actually relies on the constructor chain being broken
(Such as checking for c.constructor===A&&c.propertyInheritedOnlyFromC
because c.constructor===C was false when the developer tried that, in
your original example.) Remember that a lot of developers don't code
to the spec, they code to browser behaviour. If browser behaviour
doesn't make sense, they do workarounds. They could have made better
workarounds than that if they were aware of the cause of the actual
problem, but most of them are not.






> ES4 ref impl seems a bit off:
>
> >> (new function F(){}).constructor
> [function Function]
> >> new Date(9e9).constructor
> [class Class]
> >> 1['constructor']
> [class Class]

Seems a bit broken, yes...


> It appears that es4 ref impl has the correct result for instancof on primitives
>
> All are true in ES4 and false in ES3:
> true instanceof Boolean
> "oo" instanceof String
> 2 instanceof Number
> null instanceof Object
> NaN instanceof Number
> Number.Infinity instanceof Number
>
> I think the change is correct. if typeof b == "boolean", b instanceof
> boolean seems like it must be true.

A bugfix, IIRC.
-- 
David "liorean" Andersson



More information about the Es4-discuss mailing list