|
The Gravey 2.5 Framework and AIM RIA | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||
Collection of routines to emulate Java-like classes in JavaScript.
A detailed explanation of the functionality of this file can
be found in the AJAX from Scratch
series of articles.
Version: 2.5
Requires:
| Class Summary | |
| GrvObject | This is the root class for all "classes" implemented via the GLOBALS.Class() function (ala Java "Object"). |
| Method Summary | |
static Function
|
Class( <Function> theClass, <StringArray> optConstructorArgDescArray )
Declare a class and create the glue objects and code to allow "pretty" source; A mechanism is set up to insure that required constructor parameters each have a defined value; This function also defines the "name" attribute of the specified class and initializes it with the class name. |
static Function
|
grvExtends( <Function> superClass )
This utility function takes (via "THIS") a "class" and (re)sets its superClass. |
static String
|
grvFuncName(<Function> f)
This function returns the name of a given function; It does this by using a regular expression to extract the function name from the function source code. |
// This file uses JSDoc-friendly comments [ http://jsdoc.sourceforge.net/ ] /** * @file grvClass.js * @fileoverview Collection of routines to emulate Java-like classes in JavaScript. * A detailed explanation of the functionality of this file can * be found in the <a target="_blank" * href="http://www.polyglotinc.com/AJAXscratch/Class">AJAX from Scratch</a> * series of articles. * * @author Bruce Wallace (PolyGlotInc.com) * @version 2.5 * @requires grvUtils.js (only for compile tracing) * @requires grvValidate.js (optional; only required if validating constructor args) */ ////////////////////////////////////////////////////////////////// // GRAVEY LEXICAL CODING CONVENTIONS: // (*) All private variables or functions start with "_" // (*) All variables and functions start with a lowercase letter // (*) All Classes start with an uppercase letter // (*) All Class methods and instance variables start with lowercase // (*) All Class "static" methods and variables start with uppercase // (*) All constants start with "k" // (*) All global variables start with "g" // (*) All event handler functions start with "on" // // (*) All Gravey utility global variables start with "gGrv" // (*) All Gravey MVC global variables start with "gMVC" // (*) All Gravey EDO global variables start with "gEDO" // (*) All Gravey utility functions start with "grv" // (*) All Gravey MVC functions start with "mvc" // (*) All Gravey MVC event handler functions start with "onMVC" // (*) All Gravey EDO event handler functions start with "onEDO" // (*) All Gravey MVC classes start with "MVC" // (*) All Gravey EDO classes start with "EDO" ////////////////////////////////////////////////////////////////// grvTraceCmp("grvClass.js: Begin"); /** * This function returns the name of a given function; It does this by * using a regular expression to extract the function name from the * function source code. * @param {Function} f reference to a function * @return name of given function * @type String * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function grvFuncName(f) { var s = f.toString().match(/function\s*(\S*)\s*\(/)[1]; return s ? s : "anonymous"; } Class(GrvObject); /** * @class This is the root class for all "classes" implemented * via the {@link GLOBALS#Class} function (ala Java "Object"). * Class replaces the normal Javascript "constructor" function * with a new wrapper function that implements a robust * inheritence mechanism. * This mechanism supports "pretty" source code whereby * "methods" are declared inline, but the source code of * those methods are not copied into every object instance * as would otherwise be the case.<p> * The wrapper function also sets up a real "constructor" * that can use {@link GLOBALS#grvValidateArgs} to insure * that the required parameters are passed to it, throwing * an exception if not.<p> * The design pattern implemented by Class/Extends corrects * several problems that occur with the naive inheritence * mechanisms often used with Javascript. *<pre> * The required coding convention for "GrvObject": * (1) the "class" is declared via the utility * function {@link GLOBALS#Class} * (2) the "superclass" (if any) is declared via the * .Extends method {@link GLOBALS#grvExtends} * (3) the "constructor" logic for the class is placed * in a "method" named "konstructor" * (4) the konstructor method invokes the "super" constructor * via its class name [rather than literally "super()"] *</pre> * @throws grvMissingArgException thrown by constructor wrapper * @see GLOBALS#Class * @see GLOBALS#grvExtends * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function GrvObject() { /** Invokes the "super" version of whatever method that is calling souper. * @return either the return value of the super method or null if no super exists */ this.souper = function() { var superMethod = this.souper.caller.souper; return (superMethod) ? superMethod.apply( this, arguments ) : null; } } /** * This utility function takes (via "THIS") a "class" and * (re)sets its superClass. * THIS VERSION SETS UP "super" ACCESS TO OVERRIDDEN METHODS. * @param {Function} superClass the "superclass constructor" function * @return a reference to the "class object" * @type Function * @see #Class * @see GrvObject * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function grvExtends( superClass ) { /////////////////////////////////////////////////////////////////// // NOTE: At this point superClass should have already had its own // Class and Extends calls performed. I.E. "declare" superclasses // BEFORE those classes that extend them. /////////////////////////////////////////////////////////////////// if (!superClass.baseClass) throw "Undeclared Super Class in .Extends"; //get superclass exemplar but avoid infinite recursion on implied root class var superexemplar = (this==GrvObject) ? null : (superClass ? superClass.prototype : null); //Recall that one can't change the exemplar.__proto__ property directly //SO, one must create a new exemplar instance after baseClass.prototype is set. this.baseClass.prototype = superexemplar; var exemplar = new this.baseClass(); //for each method in exemplar, if there is a different method with the //same name in superexemplar, setup the .souper link between them. var s,m; if (superexemplar) for (var property in exemplar)// iterate over all properties { m = exemplar[property]; s = superexemplar[property]; if (s && (s!=m) && (m instanceof Function) && (s instanceof Function)) m.souper = s; } //Note that it would normally be a problem if Extends were called after //someone has already created an instance of "this" class (via new). //However, that situation should never occur since all the calls to Class() //and Extends() are normally done at web page load time, and application //logic should only start after the page "onload" event, hence all these //exemplars should be stable. this.prototype = exemplar; this.prototype.name = this.cname;//default value // while "souper" works with konstructor, some may still prefer to // use the superclass name explicitly when invoking its constructor // so we leave this in to continue support for that. this.prototype[this.cname] = this.prototype.konstructor; return this; } /** * Declare a class and create the glue objects and code * to allow "pretty" source; A mechanism is set up to insure * that required constructor parameters each have a defined value; * This function also defines the "name" attribute of the specified * class and initializes it with the class name. * @param {Function} theClass the "class constructor" function * @param {StringArray} optConstructorArgDescArray optional array * of strings describing required parameters for this class' * "constructor"; Note: Optional constructor parameters should * not be included in this array. * @return the "class object" (an extended Function object) * @type Function * @see #Extends * @see #grvValidateArgs * @see GrvObject * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function Class( theClass, optConstructorArgDescArray ) { // The "class" as passed in will really be an abstract base class. We // will squirrel that away and replace theClass with a wrapper function // so that method source code is not copied into each object instance // as would otherwise be the case. var baseClass = theClass; // create the new wrapper function to replace theClass var className = grvFuncName( theClass ); self[className] = theClass = function(){ var C = arguments.callee; if (C.required && self["grvValidateArgs"]!==void 0) grvValidateArgs( C.cname, C.required, arguments ); C.prototype.konstructor.apply( this, arguments ); } theClass.required = optConstructorArgDescArray; theClass.cname = className;//FYI,netscape&firefox break with ".name" theClass.baseClass = baseClass; theClass.Extends = grvExtends; //so we can call grvExtends as a method return theClass.Extends(GrvObject); //required here even if overridden later } grvTraceCmp("grvClass.js: End");
|
The Gravey 2.5 Framework and AIM RIA | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||