1
0
Fork 0

Public static properties references are now shared with subtypes

closure/master
Mike Gerwitz 2011-04-10 22:32:46 -04:00
parent aead20290c
commit 4a90b7b809
2 changed files with 57 additions and 31 deletions

View File

@ -160,7 +160,10 @@ exports.build = function extend()
prop_init = member_builder.initMembers(),
members = member_builder.initMembers( prototype ),
static_members = member_builder.initMembers(),
static_members = {
methods: member_builder.initMembers(),
props: member_builder.initMembers(),
}
abstract_methods =
util.clone( exports.getMeta( base ).abstractMethods )
@ -204,11 +207,11 @@ exports.build = function extend()
var new_class = createCtor( cname, abstract_methods, members );
// closure to hold static initialization to be used later by subtypes
var staticInit = function( ctor )
var staticInit = function( ctor, inheriting )
{
attachStatic( ctor, static_members, base );
attachStatic( ctor, static_members, base, inheriting );
}
staticInit( new_class );
staticInit( new_class, false );
attachPropInit( prototype, prop_init, members, class_id );
@ -394,7 +397,11 @@ function buildMembers(
)
{
var hasOwn = Array.prototype.hasOwnProperty,
defs = {};
defs = {},
smethods = static_members.methods,
sprops = static_members.props
;
util.propParse( props, {
each: function( name, value, keywords )
@ -424,7 +431,7 @@ function buildMembers(
property: function( name, value, keywords )
{
var dest = ( keywords[ 'static' ] ) ? static_members : prop_init;
var dest = ( keywords[ 'static' ] ) ? sprops : prop_init;
// build a new property, passing in the other members to compare
// against for preventing nonsensical overrides
@ -435,7 +442,7 @@ function buildMembers(
getter: function( name, value, keywords )
{
var dest = ( keywords[ 'static' ] ) ? static_members : members;
var dest = ( keywords[ 'static' ] ) ? smethods : members;
member_builder.buildGetter(
dest, null, name, value, keywords
@ -444,7 +451,7 @@ function buildMembers(
setter: function( name, value, keywords )
{
var dest = ( keywords[ 'static' ] ) ? static_members : members;
var dest = ( keywords[ 'static' ] ) ? smethods : members;
member_builder.buildSetter(
dest, null, name, value, keywords
@ -453,7 +460,7 @@ function buildMembers(
method: function( name, func, is_abstract, keywords )
{
var dest = ( keywords[ 'static' ] ) ? static_members : members;
var dest = ( keywords[ 'static' ] ) ? smethods : members;
// constructor check
if ( public_methods[ name ] === true )
@ -560,24 +567,47 @@ function attachPropInit( prototype, properties, members, cid )
/**
* Attaches static members to a constructor (class)
*
* Static methods will be assigned to the constructor itself. Properties, on the
* other hand, will be assigned to ctor.$. The reason for this is because JS
* engines pre-ES5 support no means of sharing references to primitives. Static
* properties of subtypes should share references to the static properties of
* their parents.
*
* @param {function()} ctor class
* @param {Object} members static members
* @param {function()} base base class inheriting from
* @param {boolean} inheriting true if inheriting static members,
* otherwise false (setting own static
* members)
*
* @return {undefined}
*/
function attachStatic( ctor, members, base )
function attachStatic( ctor, members, base, inheriting )
{
// "inherit" the parent's static members by running the parent's static
var methods = members.methods,
props = members.props;
// "inherit" the parent's static methods by running the parent's static
// initialization method
var baseinit = base.___$$sinit$$;
if ( baseinit )
{
baseinit( ctor );
baseinit( ctor, true );
}
// initialize static property if not yet defined
if ( !inheriting )
{
// "inherit" properties from the supertype, if available
ctor.$ = base.$ || {};
// add our own properties
util.copyTo( ctor.$, props[ 'public' ], true );
}
// copy over public static members (deep copy; we don't want subtypes to
// share references with their parents)
util.copyTo( ctor, members[ 'public' ], true );
util.copyTo( ctor, methods[ 'public' ], true );
}

View File

@ -79,13 +79,13 @@ var common = require( './common' ),
} );
// properties should be accessible via class definition
assert.equal( Foo.foo, val,
assert.equal( Foo.$.foo, val,
"Public static properties should be accessible via class definition"
);
// as long as the above test succeeded, we can then conclude that static
// members are public by default if the following succeeds
assert.equal( Foo.bar, val2,
assert.equal( Foo.$.bar, val2,
"Static properties are public by default"
);
@ -240,10 +240,10 @@ var common = require( './common' ),
;
// properties
assert.equal( SubFoo.foo, Foo.foo,
assert.equal( SubFoo.$.foo, Foo.$.foo,
"Public static properties are inherited by subtypes"
);
assert.equal( SubSubFoo.foo, Foo.foo,
assert.equal( SubSubFoo.$.foo, Foo.$.foo,
"Public static properties are inherited by sub-subtypes"
);
@ -256,7 +256,7 @@ var common = require( './common' ),
);
// merge
assert.equal( SubFoo.baz, baz,
assert.equal( SubFoo.$.baz, baz,
"Subtypes contain both inherited static members as well as their own"
);
@ -288,10 +288,11 @@ var common = require( './common' ),
/**
* Each class should have its own set of static values. That is, a subtype
* should not share references with its parent.
* Static references should be inherited by subtypes. That is, modifying a
* static property of a supertype should modify the same static property of the
* subtype, so long as the subtype has not defined a property of the same name.
*/
( function testInheritedPublicStaticPropertiesAreClones()
( function testPublicStaticPropertyReferencesAreInheritedBySubtypes()
{
var val = [ 1, 2, 3 ],
Foo = builder.build(
@ -301,14 +302,9 @@ var common = require( './common' ),
SubFoo = builder.build( Foo, {} )
;
// the values should certainly be equal...
assert.deepEqual( SubFoo.bar, Foo.bar,
"Inherited static properties should be equal by value"
);
// ...but they should not be the same object
assert.ok( SubFoo.bar !== Foo.bar,
"Inherited static propertis should not be the same object"
// the properties should reference the same object
assert.ok( SubFoo.$.bar === Foo.$.bar,
"Inherited static properties should share references"
);
} )();