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(),
|
prop_init = member_builder.initMembers(),
|
||||||
members = member_builder.initMembers( prototype ),
|
members = member_builder.initMembers( prototype ),
|
||||||
static_members = member_builder.initMembers(),
|
static_members = {
|
||||||
|
methods: member_builder.initMembers(),
|
||||||
|
props: member_builder.initMembers(),
|
||||||
|
}
|
||||||
|
|
||||||
abstract_methods =
|
abstract_methods =
|
||||||
util.clone( exports.getMeta( base ).abstractMethods )
|
util.clone( exports.getMeta( base ).abstractMethods )
|
||||||
|
@ -204,11 +207,11 @@ exports.build = function extend()
|
||||||
var new_class = createCtor( cname, abstract_methods, members );
|
var new_class = createCtor( cname, abstract_methods, members );
|
||||||
|
|
||||||
// closure to hold static initialization to be used later by subtypes
|
// 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 );
|
attachPropInit( prototype, prop_init, members, class_id );
|
||||||
|
|
||||||
|
@ -394,7 +397,11 @@ function buildMembers(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var hasOwn = Array.prototype.hasOwnProperty,
|
var hasOwn = Array.prototype.hasOwnProperty,
|
||||||
defs = {};
|
defs = {},
|
||||||
|
|
||||||
|
smethods = static_members.methods,
|
||||||
|
sprops = static_members.props
|
||||||
|
;
|
||||||
|
|
||||||
util.propParse( props, {
|
util.propParse( props, {
|
||||||
each: function( name, value, keywords )
|
each: function( name, value, keywords )
|
||||||
|
@ -424,7 +431,7 @@ function buildMembers(
|
||||||
|
|
||||||
property: function( name, value, keywords )
|
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
|
// build a new property, passing in the other members to compare
|
||||||
// against for preventing nonsensical overrides
|
// against for preventing nonsensical overrides
|
||||||
|
@ -435,7 +442,7 @@ function buildMembers(
|
||||||
|
|
||||||
getter: function( name, value, keywords )
|
getter: function( name, value, keywords )
|
||||||
{
|
{
|
||||||
var dest = ( keywords[ 'static' ] ) ? static_members : members;
|
var dest = ( keywords[ 'static' ] ) ? smethods : members;
|
||||||
|
|
||||||
member_builder.buildGetter(
|
member_builder.buildGetter(
|
||||||
dest, null, name, value, keywords
|
dest, null, name, value, keywords
|
||||||
|
@ -444,7 +451,7 @@ function buildMembers(
|
||||||
|
|
||||||
setter: function( name, value, keywords )
|
setter: function( name, value, keywords )
|
||||||
{
|
{
|
||||||
var dest = ( keywords[ 'static' ] ) ? static_members : members;
|
var dest = ( keywords[ 'static' ] ) ? smethods : members;
|
||||||
|
|
||||||
member_builder.buildSetter(
|
member_builder.buildSetter(
|
||||||
dest, null, name, value, keywords
|
dest, null, name, value, keywords
|
||||||
|
@ -453,7 +460,7 @@ function buildMembers(
|
||||||
|
|
||||||
method: function( name, func, is_abstract, keywords )
|
method: function( name, func, is_abstract, keywords )
|
||||||
{
|
{
|
||||||
var dest = ( keywords[ 'static' ] ) ? static_members : members;
|
var dest = ( keywords[ 'static' ] ) ? smethods : members;
|
||||||
|
|
||||||
// constructor check
|
// constructor check
|
||||||
if ( public_methods[ name ] === true )
|
if ( public_methods[ name ] === true )
|
||||||
|
@ -560,24 +567,47 @@ function attachPropInit( prototype, properties, members, cid )
|
||||||
/**
|
/**
|
||||||
* Attaches static members to a constructor (class)
|
* 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 {function()} ctor class
|
||||||
* @param {Object} members static members
|
* @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}
|
* @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
|
// initialization method
|
||||||
var baseinit = base.___$$sinit$$;
|
var baseinit = base.___$$sinit$$;
|
||||||
if ( baseinit )
|
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
|
// copy over public static members (deep copy; we don't want subtypes to
|
||||||
// share references with their parents)
|
// 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
|
// 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"
|
"Public static properties should be accessible via class definition"
|
||||||
);
|
);
|
||||||
|
|
||||||
// as long as the above test succeeded, we can then conclude that static
|
// as long as the above test succeeded, we can then conclude that static
|
||||||
// members are public by default if the following succeeds
|
// 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"
|
"Static properties are public by default"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -240,10 +240,10 @@ var common = require( './common' ),
|
||||||
;
|
;
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
assert.equal( SubFoo.foo, Foo.foo,
|
assert.equal( SubFoo.$.foo, Foo.$.foo,
|
||||||
"Public static properties are inherited by subtypes"
|
"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"
|
"Public static properties are inherited by sub-subtypes"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ var common = require( './common' ),
|
||||||
);
|
);
|
||||||
|
|
||||||
// merge
|
// merge
|
||||||
assert.equal( SubFoo.baz, baz,
|
assert.equal( SubFoo.$.baz, baz,
|
||||||
"Subtypes contain both inherited static members as well as their own"
|
"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
|
* Static references should be inherited by subtypes. That is, modifying a
|
||||||
* should not share references with its parent.
|
* 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 ],
|
var val = [ 1, 2, 3 ],
|
||||||
Foo = builder.build(
|
Foo = builder.build(
|
||||||
|
@ -301,14 +302,9 @@ var common = require( './common' ),
|
||||||
SubFoo = builder.build( Foo, {} )
|
SubFoo = builder.build( Foo, {} )
|
||||||
;
|
;
|
||||||
|
|
||||||
// the values should certainly be equal...
|
// the properties should reference the same object
|
||||||
assert.deepEqual( SubFoo.bar, Foo.bar,
|
assert.ok( SubFoo.$.bar === Foo.$.bar,
|
||||||
"Inherited static properties should be equal by value"
|
"Inherited static properties should share references"
|
||||||
);
|
|
||||||
|
|
||||||
// ...but they should not be the same object
|
|
||||||
assert.ok( SubFoo.bar !== Foo.bar,
|
|
||||||
"Inherited static propertis should not be the same object"
|
|
||||||
);
|
);
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue