Now properly handling extending from objects and properly throwing errors for scalars
parent
d5ef3eb221
commit
2136ebedd5
|
@ -294,7 +294,7 @@ exports.prototype.build = function extend( _, __ )
|
|||
var args = Array.prototype.slice.call( arguments ),
|
||||
props = args.pop() || {},
|
||||
base = args.pop() || exports.ClassBase,
|
||||
prototype = new base(),
|
||||
prototype = this._getBase( base ),
|
||||
cname = '',
|
||||
|
||||
prop_init = this._memberBuilder.initMembers(),
|
||||
|
@ -309,12 +309,6 @@ exports.prototype.build = function extend( _, __ )
|
|||
|| { __length: 0 }
|
||||
;
|
||||
|
||||
// must extend from constructor or class
|
||||
if ( typeof base !== 'function' )
|
||||
{
|
||||
throw TypeError( "Must extend from class or constructor");
|
||||
}
|
||||
|
||||
// prevent extending final classes
|
||||
if ( base.___$$final$$ === true )
|
||||
{
|
||||
|
@ -424,6 +418,27 @@ exports.prototype.build = function extend( _, __ )
|
|||
};
|
||||
|
||||
|
||||
exports.prototype._getBase = function( base )
|
||||
{
|
||||
var type = ( typeof base );
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
// constructor (we could also check to ensure that the return value of
|
||||
// the constructor is an object, but that is not our concern)
|
||||
case 'function':
|
||||
return new base();
|
||||
|
||||
// we can use objects as the prototype directly
|
||||
case 'object':
|
||||
return base;
|
||||
}
|
||||
|
||||
// scalars
|
||||
throw TypeError( 'Must extend from Class, constructor or object' );
|
||||
};
|
||||
|
||||
|
||||
exports.prototype.buildMembers = function buildMembers(
|
||||
props, class_id, base, prop_init, abstract_methods, members,
|
||||
static_members, staticInstLookup
|
||||
|
@ -758,11 +773,12 @@ exports.prototype._attachPropInit = function(
|
|||
// defaults to false
|
||||
inherit = !!inherit;
|
||||
|
||||
var iid = this.__iid;
|
||||
var iid = this.__iid,
|
||||
parent = prototype.___$$parent$$;
|
||||
|
||||
// first initialize the parent's properties, so that ours will overwrite
|
||||
// them
|
||||
var parent_init = prototype.___$$parent$$.__initProps;
|
||||
var parent_init = parent && parent.__initProps;
|
||||
if ( typeof parent_init === 'function' )
|
||||
{
|
||||
// call the parent prop_init, letting it know that it's been
|
||||
|
|
|
@ -432,3 +432,34 @@ for ( var i = 0; i < class_count; i++ )
|
|||
assert.fail( "Should not be permitted to override non-virtual method" );
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* If we attempt to extend an object (rather than a constructor), we should
|
||||
* simply use that as the prototype directly rather than attempting to
|
||||
* instantiate it.
|
||||
*/
|
||||
( function testExtendingObjectWillNotAttemptInstantiation()
|
||||
{
|
||||
var obj = { foo: 'bar' };
|
||||
|
||||
assert.equal( obj.foo, Class.extend( obj, {} )().foo,
|
||||
'Should be able to use object as prototype'
|
||||
);
|
||||
} )();
|
||||
|
||||
|
||||
/**
|
||||
* It only makes sense to extend from an object or function (constructor, more
|
||||
* specifically)
|
||||
*
|
||||
* We could also test to ensure that the return value of the constructor is an
|
||||
* object, but that is unnecessary for the time being.
|
||||
*/
|
||||
( function testWillThrowExceptionIfNonObjectOrCtorIsProvided()
|
||||
{
|
||||
assert['throws']( function()
|
||||
{
|
||||
Class.extend( 'foo', {} );
|
||||
}, TypeError, 'Should not be able to extend from non-object or non-ctor' );
|
||||
} )();
|
||||
|
||||
|
|
Loading…
Reference in New Issue