Class metadata is now stored in class object (first step in working with GC)
parent
7b766c1b14
commit
66758500e6
49
lib/class.js
49
lib/class.js
|
@ -27,14 +27,6 @@ var util = require( './util' ),
|
|||
propobj = require( './propobj' )
|
||||
;
|
||||
|
||||
/**
|
||||
* Stores class metadata internally (ensures data is encapsulated)
|
||||
*
|
||||
* The data in this object is hashed a class id.
|
||||
*
|
||||
* @type {Object.<number, { implemented: Array.<string> }>}
|
||||
*/
|
||||
var class_meta = {};
|
||||
|
||||
/**
|
||||
* Stores class instance visibility object
|
||||
|
@ -217,7 +209,7 @@ module.exports.isInstanceOf = function( type, instance )
|
|||
|
||||
// if no metadata is available, then our remaining checks cannot be
|
||||
// performed
|
||||
if ( !instance.__cid || !( meta = getMeta( instance.__cid ) ) )
|
||||
if ( !instance.__cid || !( meta = getMeta( instance ) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -450,7 +442,7 @@ var extend = ( function( extending )
|
|||
members = member_builder.initMembers( prototype ),
|
||||
|
||||
abstract_methods =
|
||||
util.clone( getMeta( base.__cid ).abstractMethods )
|
||||
util.clone( getMeta( base ).abstractMethods )
|
||||
|| { __length: 0 }
|
||||
;
|
||||
|
||||
|
@ -543,7 +535,7 @@ var extend = ( function( extending )
|
|||
} );
|
||||
|
||||
// reference to the parent prototype (for more experienced users)
|
||||
prototype.parent = base.prototype;
|
||||
prototype.___$$parent$$ = base.prototype;
|
||||
|
||||
// set up the new class
|
||||
var new_class = createCtor( cname, abstract_methods, members );
|
||||
|
@ -556,15 +548,15 @@ var extend = ( function( extending )
|
|||
// important: call after setting prototype
|
||||
setupProps( new_class, abstract_methods, class_id );
|
||||
|
||||
// create internal metadata for the new class
|
||||
var meta = createMeta( new_class, base );
|
||||
meta.abstractMethods = abstract_methods;
|
||||
meta.name = cname;
|
||||
|
||||
// lock down the new class (if supported) to ensure that we can't add
|
||||
// members at runtime
|
||||
util.freeze( new_class );
|
||||
|
||||
// create internal metadata for the new class
|
||||
var meta = createMeta( new_class, base.prototype.__cid );
|
||||
meta.abstractMethods = abstract_methods;
|
||||
meta.name = cname;
|
||||
|
||||
// we're done with the extension process
|
||||
extending = false;
|
||||
|
||||
|
@ -724,7 +716,7 @@ var implement = function()
|
|||
|
||||
// create a new class with the implemented abstract methods
|
||||
var class_new = module.exports.extend( base, dest );
|
||||
getMeta( class_new.__cid ).implemented = implemented;
|
||||
getMeta( class_new ).implemented = implemented;
|
||||
|
||||
return class_new;
|
||||
}
|
||||
|
@ -801,7 +793,7 @@ function attachPropInit( prototype, properties, members, cid )
|
|||
|
||||
// first initialize the parent's properties, so that ours will overwrite
|
||||
// them
|
||||
var parent_init = prototype.parent.__initProps;
|
||||
var parent_init = prototype.___$$parent$$.__initProps;
|
||||
if ( parent_init instanceof Function )
|
||||
{
|
||||
// call the parent prop_init, letting it know that it's been
|
||||
|
@ -952,29 +944,34 @@ function attachInstanceOf( instance )
|
|||
/**
|
||||
* Initializes class metadata for the given class
|
||||
*
|
||||
* @param {Class} func class to initialize metadata for
|
||||
* @param {Class} func class to initialize metadata for
|
||||
* @param {Class} cparent class parent
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
function createMeta( func, parent_id )
|
||||
function createMeta( func, cparent )
|
||||
{
|
||||
var id = func.__cid,
|
||||
parent_meta = ( ( parent_id ) ? getMeta( parent_id ) : undefined );
|
||||
parent_meta = ( ( cparent.__cid ) ? getMeta( cparent ) : undefined );
|
||||
|
||||
// copy the parent prototype's metadata if it exists (inherit metadata)
|
||||
if ( parent_meta )
|
||||
{
|
||||
class_meta[ id ] = util.clone( parent_meta, true );
|
||||
func.___$$meta$$ = util.clone( parent_meta, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
// create empty
|
||||
class_meta[ id ] = {
|
||||
func.___$$meta$$ = {
|
||||
implemented: [],
|
||||
};
|
||||
}
|
||||
|
||||
return class_meta[ id ];
|
||||
// store the metadata in the prototype as well (inconsiderable overhead;
|
||||
// it's just a reference)
|
||||
func.prototype.___$$meta$$ = func.___$$meta$$;
|
||||
|
||||
return func.___$$meta$$;
|
||||
}
|
||||
|
||||
|
||||
|
@ -988,9 +985,9 @@ function createMeta( func, parent_id )
|
|||
*
|
||||
* @return {Object}
|
||||
*/
|
||||
function getMeta( id )
|
||||
function getMeta( cls )
|
||||
{
|
||||
return class_meta[ id ] || {};
|
||||
return cls.___$$meta$$ || {};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,11 +60,6 @@ var common = require( './common' ),
|
|||
{
|
||||
return this.__super( arg );
|
||||
},
|
||||
|
||||
callParentAlt: function()
|
||||
{
|
||||
return this.parent.myMethod2.apply( this, arguments );
|
||||
},
|
||||
}),
|
||||
|
||||
foo = new Foo(),
|
||||
|
@ -109,19 +104,6 @@ assert.equal(
|
|||
"Arguments should be passed to super method via _super argument list"
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
SubFoo.prototype.parent,
|
||||
Foo.prototype,
|
||||
"Parent property should represent parent prototype"
|
||||
);
|
||||
|
||||
sub_foo.callParentAlt( arg = 'moo' );
|
||||
assert.equal(
|
||||
method2Arg,
|
||||
arg,
|
||||
"The parent property may also be used to invoke parent methods"
|
||||
);
|
||||
|
||||
assert.throws( function()
|
||||
{
|
||||
Foo.extend(
|
||||
|
|
Loading…
Reference in New Issue