13.2.2 [[Construct]], constructor, and [[Class]] (was __proto__)
Garrett Smith
dhtmlkitchen at gmail.com
Sun Sep 23 02:05:28 PDT 2007
On 9/22/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!
> 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.)
>
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.)
1. The constructor property should be on the object instance *created*
by the function.
<snip>
> > How about a constructor property on the function instance?
2. (new function(){}).constructor should be Function.
But you understood what I meant even though I said it wrong. I meant
to say that the object instance's constructor property should be the
Function that "new" was called on.
> 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.
<snip>
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.
(new F).constructor; // should be F.
The constructor property should match the [[Construct]] property. This
should happen right before the prototype. Here's 13.2.2 with my edits:
13.2.2 [[Construct]]
When the [[Construct]] property for a Function object F is called,
the following steps are taken:
1. Create a new native ECMAScript object.
2. Set the [[Class]] property of Result(1) to "Object".
--> ∆ set the [[Class]] of o to reflect the name F <--
3. Get the value of the prototype property of F.
--> Set the constructor property of Result(1) to F <--
4. If Result(3) is an object, set the [[Prototype]] property of
Result(1) to Result(3).
5. If Result(3) is not an object, set the [[Prototype]] property
of Result(1) to the original Object prototype object as described in
15.2.3.1.
6. Invoke the [[Call]] property of F, providing Result(1) as the
this value and providing the argument list passed into [[Construct]]
as the argument values.
7. If Type(Result(6)) is Object then return Result(6).
8. Return Result(1).
∆ Note: Although allowed in ES3, Functions used as constructors should
not return a value. (reword)
> probably wouldn't hurt much code out there.
What could it hurt? What would get broken?
Benefits:
1) can crawl up the constructors without having to bake the
functionality into your library,
2) Doesn't force clients to use a non-standard fix.
3) [[class]] matches constructor property
The flip side of (2) is that if it stays, a client of a library that
"fixes" the constructor property may have objects created by an
in-house or another third party library where the library doesn't fix
the constructor property.
The constructor property is modifiable, but you cant count on third
party libraries using the same modification (I call it a nonstandard
"fix") to the constructor property.
ES4 ref impl seems a bit off:
>> (new function F(){}).constructor
[function Function]
>> new Date(9e9).constructor
[class Class]
>> 1['constructor']
[class Class]
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.
I would like to understand why it was not working right in ES3-, if
someone can explain.
Garrett
> David "liorean" Andersson
More information about the Es4-discuss
mailing list