From f632b93d6496f80fad507a1f0f9b209c881d10c8 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Mon, 15 Nov 2010 07:07:49 -0500 Subject: [PATCH] Refactored constructor creation logic for new classes into its own method and placed both functions (and their shared var) into a closure to remove the 'extending' var from the module's scope --- lib/class.js | 131 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 53 deletions(-) diff --git a/lib/class.js b/lib/class.js index 6a33b92..55cca98 100644 --- a/lib/class.js +++ b/lib/class.js @@ -81,77 +81,102 @@ function Class() {}; /** - * Set to TRUE when class is being extended to allow the instantiation of - * abstract classes (for use in prototypes) + * Creates extend function * - * @var {boolean} + * The 'extending' parameter is used to override the functionality of abstract + * class constructors, allowing them to be instantiated for use in a subclass's + * prototype. + * + * @param {boolean} extending whether a class is currently being extended + * + * @return {Function} extend function */ -var extending = false; - -/** - * Mimics class inheritance - * - * This method will mimic inheritance by setting up the prototype with the - * provided base class (or, by default, Class) and copying the additional - * properties atop of it. - * - * The class to inherit from (the first argument) is optional. If omitted, the - * first argument will be considered to be the properties list. - * - * @return {Object} extended class - */ -function extend() +var extend = ( function( extending ) { - // ensure we'll be permitted to instantiate abstract classes for the base - extending = true; + extending = false; - var args = Array.prototype.slice.call( arguments ), - props = args.pop() || {}, - base = args.pop() || Class, - prototype = new base(); + /** + * Mimics class inheritance + * + * This method will mimic inheritance by setting up the prototype with the + * provided base class (or, by default, Class) and copying the additional + * properties atop of it. + * + * The class to inherit from (the first argument) is optional. If omitted, the + * first argument will be considered to be the properties list. + * + * @return {Object} extended class + */ + return function extend() + { + // ensure we'll be permitted to instantiate abstract classes for the base + extending = true; - // copy the given properties into the new prototype - var result_data = { - abstractMethods: ( base.abstractMethods || [] ).slice() - }; - prop_copy( props, prototype, result_data ); + var args = Array.prototype.slice.call( arguments ), + props = args.pop() || {}, + base = args.pop() || Class, + prototype = new base(); - // reference to the parent prototype (for more experienced users) - prototype.parent = base.prototype; + // copy the given properties into the new prototype + var result_data = { + abstractMethods: ( base.abstractMethods || [] ).slice() + }; + prop_copy( props, prototype, result_data ); - var new_class = ( result_data.abstractMethods.length === 0 ) - ? ( - // concrete class - function() + // reference to the parent prototype (for more experienced users) + prototype.parent = base.prototype; + + // set up the new class + var new_class = create_ctor( result_data, extending ); + + setup_props( new_class, result_data ); + new_class.prototype = prototype; + new_class.constructor = new_class; + + // we're done with the extension process + extending = false; + + return new_class; + } + + + /** + * Creates the constructor for a new class + * + * This constructor will call the __constructor method for concrete classes + * and throw an exception for abstract classes (to prevent instantiation). + * + * @param {Object} result_data data from property copy operation + * + * @return {Function} constructor + */ + function create_ctor( result_data ) + { + // concrete class + if ( result_data.abstractMethods.length === 0 ) + { + return function() { if ( this.__construct instanceof Function ) { // call the constructor this.__construct.apply( this, arguments ); } - } - ) - : ( - // do not allow abstract classes to be instantiated - function () + }; + } + // abstract class + else + { + return function () { if ( !extending ) { throw new Error( "Abstract classes cannot be instantiated" ); } - } - ); - - // set up the new class - setup_props( new_class, result_data ); - new_class.prototype = prototype; - new_class.constructor = new_class; - - // we're done with the extension process - extending = false; - - return new_class; -} + }; + } + } +} )(); /**