> On Feb 6, 2015, at 10:35 AM, Claude Pache <[email protected]> wrote:
>
>>
>> Le 6 févr. 2015 à 18:04, Ben Newman <[email protected]
>> <mailto:[email protected]>> a écrit :
>>
>> The specific line in rev32 of the spec that prevents [[Call]]ing
>> "classConstructor" functions is 9.2.2.2
>> <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-function-objects-call-thisargument-argumentslist>:
>>
>> 2. If F’s [[FunctionKind]] internal slot
>> <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object-internal-methods-and-internal-slots>
>> is "classConstructor", throw a TypeError exception.
>>
>> From my reading of the spec, I think the idiomatic Foo.call(this) pattern
>> that Luke Scott described would work if we simply changed that line to
>> something slightly weaker:
>>
>> 2. If F’s [[FunctionKind]] internal slot
>> <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object-internal-methods-and-internal-slots>
>> is "classConstructor" and InstanceofOperator
>> <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-instanceofoperator>(thisArgument,
>> F) is false, throw a TypeError exception.
>>
>> This mirrors an assertion discipline that has saved me from many bugs due to
>> forgetting the new operator:
>>
>> function Base() {
>> assert.ok(this instanceof Base);
>> ...
>> }
>>
>> function Derived() {
>> assert.ok(this instanceof Derived);
>> Base.call(this);
>> ...
>> }
>>
>> Derived.prototype = Object.create(Base.prototype, {
>> constructor: { value: Derived, ... }
>> });
>>
>> Is the addition of the instanceof check naive? Would it invalidate any of
>> the assumptions involved in the invocation of F?
>>
>> I'm happy to file a bug if this change merits further consideration.
>>
>> It may be worth noting that only constructors created by class syntax will
>> have their [[FunctionKind]] internal slot set to "classConstructor", so
>> (even with the current spec) you can still invoke ordinary constructor
>> functions using [[Call]]. However, it seems regrettable that you have to
>> know whether a constructor was created by class syntax in order to know
>> whether the Foo.call(this) pattern is safe.
>
> The issue is deeper. In short, you cannot feed an ES6-class constructor with
> an already allocated object, whatever that object is.
>
> With a user-defined good ol' pre-ES6 constructor:
>
> foo = new Foo // allocate a Foo object and initialise it
>
> is usually equivalent to:
>
> foo = Object.create(Foo.prototype) // allocate a Foo object ...
> Foo.call(foo) // ... and initilise it
>
> With the new ES6-class semantics, for the sake of subclassability of
> builtins, it is, on purpose, not possible to separate allocation from
> initialisation that way. Even before ES6, builtin classes, did not support
> such a pattern, e.g.,
>
> arr = new Array(2, 3) // allocate a new array and initialise it
>
> is in no way equivalent to:
>
> arr = Object.create(Array.prototype) // allocate an new object, but it
> won't be an array...
> Array.call(arr, 2, 3) // ... and don't initialise it, but create
> uselessly a new Array
>
> And it appeared that introducing the possibility for builtins to have
> separate allocation and initialisation phases was problematic.
>
> —Claude
The following should be sufficient with the current ES6, spec, right? It
currently works in 6to5.
function mixin(classObject, …traits) {
var newClassObject = class extends classObject{}
// … fill in prototype here
}
Below is a possible workaround for pre-ES6 code (without being transpired),
provided that an Object.isClass is added (checks for internal classConstructor
flag), which would always return false in pollyfills.
function mixin(classObject, traits) {
var newClassObject;
if (Object.isClass(classObject)) {
newClassObject = eval("class extends classObject{}”);
} else {
newClassObject = function() {classObject.apply(this, arguments);};
newClassObject.prototype = Object.create(classObject.prototype);
newClassObject.prototype.constructor = newClassObject;
}
// … fill in prototype here
}
It’s an ugly hack. Unfortunately the eval is necessary because Chrome throws
“Unexpected reserved word” for the class keyword.
--
Luke
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss