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

Garrett Smith dhtmlkitchen at gmail.com
Sun Sep 23 11:23:59 PDT 2007


On 9/23/07, liorean <liorean at gmail.com> wrote:
> > > 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.
>
Function objects get a non-enumerable constructor.
function F(){};
F.constructor === Function; // true
F.prototype.hasOwnProperty('constructor'); //true
F.prototype.propertyIsEnumerable("constructor"); // false.

Object instances don't, unless it's a prototype object created by [[construct]]
(new F).constructor === F.constructor; // true. Undesirable

This works fine for shallow inheritance
Objects don't get a constructor
({}).constructor === Object.prototype.constructor; // True.

Built in objects get a constructor in the prototype:
Date.prototype.constructor === Date; // True.


> > 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.
>
>
Which is different from the way built ins work, but seems OK.

>
>
> > > 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
>

function Dec(){}

var Expr = function(){};

var e = new Expr();

b.constructor; // Expr

When there is an anonymous constructor, we have the ability to get at
the constructor property.

function Animation(element){
   var looped = 0;
   var e = element;

   function construct() {
    this.loopCount = function() {
     return looped;
    }
    this.loop = function() {
     looped++;
    }
   }
   return new construct();
 }

new new Animation().constructor().constructor; // construct

>
> 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!)
>

F is a Function instance
f is a function instance

The terminology is confusing.

function F(){}
var f = new F;
f instanceof F; // true
F instanceof Function; // true

typeof f == "object"; // true.
typeof F == "function"; // true.

f.constructor === F; // true
F.constructor === Function;/ true.



f instanceof F; // true
F instanceof Function; // true

typeof f; // "object"
typeof F; // "function"

>
>
>
> > 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
> _______________________________________________
> Es4-discuss mailing list
> Es4-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es4-discuss
>


-- 
Programming is a collaborative art.



More information about the Es4-discuss mailing list