Super quick and very short reply: You can't change the prototype of an
instance by assigning to the "prototype" property. You need to write
to the (magical) __proto__ property, which is supported - though not
encouraged - by V8.
Cheers,
Kasper
My gawd, it works:
function SubType()
{
this.__proto__ = new MyNative();
print('proto =',this.prototype,'str=',this.str);
return this;
}
var sub = new SubType();
sub.str = "sub.str";
var sub2 = new SubType();
sub2.str = "sub2.str";
print(sub.str,sub2.str,sub.me(),sub2.me());
print(sub.hi(),sub2.hi());
print( sub2 instanceof MyNative );
Cool!
i know this is a magic/unportable solution, but is there any real
likelyhood that __proto__ will be removed, or only be available with
certain build- or context-specific options? Or is there another
(portable, though possibly hackish?) approach to doing this?
Thank you, Kasper!
--
----- stephan beal
http://wanderinghorse.net/home/stephan/
i'm only interested in it in the context of subclassing v8-bound
types, so portability across engines isn't a concern :).
:-D
Now i can go open up all kinds of new cans of coding worms...
<big snip>
> Key is that TempClass that allows you to swap in your parent class.
> And I don't see why you couldn't do this for a native-bound type.
Ooooh. i will certainly give that a try. i'm not nearly as intimate
with JS as i am with C++, so i can't come up with this clever stuff
myself.
Thanks :)
i wasn't able to get that to work:
subclass.js:24: TypeError: Cannot call method 'call' of undefined
this._superConstructor_.call( this );
but this change works for me:
ChildClass.prototype._superConstructor_ = ParentClass;
ChildClass.prototype._superClass_ = ParentClass.prototype;
note the insertion of ".prototype".
> Object._extends_( MySubType, MyType );
Then i hacked it a bit...
Since MySubType already subclasses Object, we can change:
Object.prototype._extends_ = function( ChildClass, ParentClass )
{
if( 1 == arguments.length )
{
return this._extends_(this,ChildClass);
}
... same as before ...
}
And:
> Object._extends_( MySubType, MyType );
becomes:
MySubType._extends_(MyType);
otherwise _extends_ might as well be a non-member function.
Thanks for that tip! This will be useful!
Need to be careful here. The intent is to modify the static class
members here. For the reason why, see below.
>
> i wasn't able to get that to work:
>
> subclass.js:24: TypeError: Cannot call method 'call' of undefined
> this._superConstructor_.call( this );
...Because I made a typo. For clarity, the _superConstructor_.call()
is referenced via SuperType._superConstructor_.call( this ). This
allows for the selection of which super constructor (really any member
method) you would like to call. So, if you have an inheritance chain
like Person->Employee->Manager, from Manager's constructor you can
call Employee._superConstructor_, or Person._superConstructor_, or
Person.setPhoneNumber or Employee.setPhoneNumber. A nice feature that
call/apply & prototypal inheritance lets you exploit.
>
> but this change works for me:
>
> ChildClass.prototype._superConstructor_ = ParentClass;
> ChildClass.prototype._superClass_ = ParentClass.prototype;
>
> note the insertion of ".prototype".
>
>> Object._extends_( MySubType, MyType );
>
> Then i hacked it a bit...
>
> Since MySubType already subclasses Object, we can change:
>
> Object.prototype._extends_ = function( ChildClass, ParentClass )
> {
> if( 1 == arguments.length )
> {
> return this._extends_(this,ChildClass);
> }
> ... same as before ...
> }
>
> And:
>
>> Object._extends_( MySubType, MyType );
>
> becomes:
>
> MySubType._extends_(MyType);
>
> otherwise _extends_ might as well be a non-member function.
>
> Thanks for that tip! This will be useful!
I don't remember at the moment, but this might breakdown for some
patterns of inheritance. I need re-read this article
(http://webreflection.blogspot.com/2007/07/javascript-prototypal-inheritance-using.html)
to explain why (at one time, I had made the same changes and it didn't
work for me and I forget which test failed).
-Louis
Aha. Okay, for clarity, here's what i've got now (which seems to work):
Object.prototype._extends_ = function( ChildClass, ParentClass )
{
if( 1 == arguments.length )
{
ParentClass = ChildClass;
ChildClass = this;
}
function TempClass() {}
TempClass.prototype = ParentClass.prototype;
ChildClass.prototype = new TempClass();
ChildClass.prototype.constructor = ChildClass;
ChildClass.prototype._superConstructor_ = ParentClass;
ChildClass.prototype._superClass_ = ParentClass.prototype;
}
Object.prototype._extends_ = function( ChildClass, ParentClass )
{
function TempClass() {}
TempClass.prototype = ParentClass.prototype;
ChildClass.prototype = new TempClass();
ChildClass.prototype.constructor = ChildClass;
ChildClass._superConstructor_ = ParentClass;
ChildClass._superClass_ = ParentClass.prototype;
};
var MyType = function()
{
var av = Array.prototype.slice.apply(arguments,[0]);
print("new MyType(",av.join(','),')');
this.prop1 = 1;
};
var MySubType = function()
{
var av = Array.prototype.slice.apply(arguments,[0]);
MySubType._superConstructor_.call( this, av );
print("new MySubType(",av.join(','),')');
this.prop2 = 2;
};
Object._extends_( MySubType, MyType );
var x = new MySubType(7,3,11);
print( x.prop1 + ":" + x.prop2 );
print( x instanceof MyType );
Output:
new MyType( 7,3,11 )
new MySubType( 7,3,11 )
1:2
true
:-?