Public static properties references are now shared with subtypes
parent
aead20290c
commit
4a90b7b809
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
} )();
|
||||
|
||||
|
|
Loading…
Reference in New Issue