//First, the basic key to all this... Function.prototype.setScope = function (scope) { //Somone give a better way to do this; eval'ing is so // bad for code quickness. with (scope) { eval('var ret='+this.toString()); } scope.member=ret; return ret; } /* Compatibility function to stand in for Prototype's highly useful bind function */ if (typeof Function.prototype.bind !== 'function') Function.prototype.bind = function (context) { var __method=this; return function () { return __method.apply(this,arguments); } } function Class(def) { var ext = function (dst,src,scope, context) { //Specially tweaked cheapo Object.extend if (typeof src=='undefined') return dst; var tmpScope={}; for (var i in src) if (typeof src[i]=='function' && typeof scope != 'undefined') { tmpScope=ext({memberName:i},scope); dst[i]=src[i].setScope(tmpScope); if (typeof context=='object') dst[i]=dst[i].bind(context); } else dst[i]=src[i]; return dst; } var instantiate; var pSelf={}; var ret=function () { instantiate.apply(this,arguments); } ret.classDef=def; //Variables which will hold exposed scopes var publicStatic={self:ret,scope:'public',type:'static'}; var privateStatic={self:ret,pSelf:pSelf,scope:'private',type:'static'}; with (publicStatic) { instantiate=function () { var i,pThis={}; var publicMember={ self:ret,scope:'public', type:'instance' }; var privateMember={ self:ret,pSelf:pSelf,pThis:pThis, scope:'private',type:'instance' }; if (typeof def.members == 'object') { ext(this,def.members.blind,publicMember); ext(this,def.members.privelidged,privateMember); ext(pThis,def.members.private,privateMember); if (!!this.initialize) this.initialize.apply(this,arguments); } } } if (!!def.static) { for (i in def.static.blind) { console.log(i); } ext(ret,def.static.blind,publicStatic); ext(ret,def.static.privelidged,privateStatic); ext(pSelf,def.static.private,privateStatic); } return ret; } // Class extend. Takes the previously stored // classDef, extends it with newDef, and creates a new Class Class.extend = function (base,newDef) { var defs=[base.classDef,newDef]; var combDef={}; var mode,scope; for (i=0; i ; I hope that means something to someone. Meanwhile, here's a quick testsuite. /* Quick and dirty compat function to get output out regardless of interpreter */ if (typeof console=='undefined') { var console={}; if (typeof WScript != 'undefined') { console.log = function (a) { WScript.Echo(a); } }else{ console.log=function (a) { alert(a); } } } /* Test class, using one of each type of member */ var X = Class({ members: { //Defined within constructor, blind: { //given class (self), instance (this) //accessible as instance.member //accessible to instance as this.member cantSee: function () { //Blind-scope members are for public //instance variables and the functions that //mess with only them var name='X'+(type=='instance'?'#':'::')+'('+scope+')'+memberName; console.log( name+": I can"+ (typeof self.cantSee!='undefined'?"":"'t")+ " see public statics" ); console.log( name+": I can"+ (typeof pSelf!='undefined'?"":"'t")+ " see private statics" ); console.log( name+": I can"+ (typeof this.cantSee!='undefined'?"":"'t")+ " see public members" ); console.log( name+": I can"+ (typeof pThis!='undefined'?"":"'t")+ " see private members" ); } }, privelidged: { //given class (self), instance (this), //class private (pSelf), instance private (pThis) //accessible as instance.member //accessible to instance as this.member //Note that collisions are possible between blind //and privelidged members, but not private initialize: function () { this.cantSee(); var name='X'+(type=='instance'?'#':'::')+'('+scope+')'+memberName; console.log( name+": I can"+ (typeof self.cantSee!='undefined'?"":"'t")+ " see public statics" ); console.log( name+": I can"+ (typeof pSelf.inHiding!='undefined'?"":"'t")+ " see private statics" ); console.log( name+": I can"+ (typeof this.cantSee!='undefined'?"":"'t")+ " see public members" ); console.log( name+": I can"+ (typeof pThis.inHiding!='undefined'?"":"'t")+ " see private members" ); pThis.inHiding(); } }, private: { //given class (self), instance (this), //class private (pSelf), instance private (pThis) //accessible to instance as pThis.member //should not exist as far as DOM tree is concerned inHiding: function () { var name='X'+(type=='instance'?'#':'::')+'('+scope+')'+memberName; console.log( name+": I can"+ (typeof self.cantSee!='undefined'?"":"'t")+ " see public statics" ); console.log( name+": I can"+ (typeof pSelf.inHiding!='undefined'?"":"'t")+ " see private statics" ); console.log( name+": I can"+ (typeof this.cantSee!='undefined'?"":"'t")+ " see public members" ); console.log( name+": I can"+ (typeof pThis.inHiding!='undefined'?"":"'t")+ " see private members" ); self.cantSee(); } } }, static: { blind: { //given class (self) //accessible as className.member //accessible to self as self.member cantSee: function () { //Probably best to stick publicly useful utility //functions and class constants here var name='X'+(type=='instance'?'#':'::')+'('+scope+')'+memberName; console.log( name+": I can"+ (typeof self.cantSee!='undefined'?"":"'t")+ " see public statics" ); console.log( name+": I can"+ (typeof pSelf!='undefined'?"":"'t")+ " see private statics" ); self.canSee(); } }, privelidged: { //given class (self), class private (pSelf) //accessible as className.member //accessible to self as self.member //Note that collisions are possible between blind //and privelidged statics, but not private canSee: function () { var name='X'+(type=='instance'?'#':'::')+'('+scope+')'+memberName; console.log( name+": I can"+ (typeof self.cantSee!='undefined'?"":"'t")+ " see public statics" ); console.log( name+": I can"+ (typeof pSelf.inHiding!='undefined'?"":"'t")+ " see private statics" ); pSelf.inHiding(); } }, private: { //given class (self), class private (pSelf) //accessible to self as pSelf.member //should not exist as far as DOM tree is concerned inHiding: function () { var name='X'+(type=='instance'?'#':'::')+'('+scope+')'+memberName; console.log( name+": I can"+ (typeof self.cantSee!='undefined'?"":"'t")+ " see public statics" ); console.log( name+": I can"+ (typeof pSelf.inHiding!='undefined'?"":"'t")+ " see private statics" ); console.log('Test ends'); } } } }); //Call the initializer! var x = new X();