JSClass Developer Documentation 0.5.1
© Bart Bizon

Introduction

JSClass , or JavaScript Class, is a client-side parser that facilitates class-based inheritance, encapsulation, accessors, simple and clean syntax and much more, in JavaScript.

JSClass is created entirely in JavaScript, and as such will be cached by the browser and no additional plugins or applications are needed.

JSClass syntax and functionality is quite inspired by Java, and intended to put the "Java" back into "JavaScript" !
Seriously speaking though, JSClass is most likely the best example of the (underestimated) powers of JavaScript.

JSClass consists of the Browser object, the Import function and the JSClass object. There are also optional JSClass modules, that provide additional functionality.


Including JSClass

Each web page/application that uses JSClass needs to include it. Since it's a single JavaScript file you include it as you would any other JavaScript file.

JSClass is designed to work in a cross browser/platform environment, using the default scripting language (i.e. JavaScript/JScript) and script version of the browsers supported. This means that you do not need to specify the scripting language nor the scripting version in JSClass scripts, e.g.

<script src="JSClassPath/JSClass.js"/>
<script> 
  //JSClass code
</script>

The browsers/platforms support list is not maintained in this document.


The Browser Object

The Browser object provides information about JSClass relevant browsers. Note that it is not a complete browser sniffer, as it ignores non-JSClass compliant browsers. Examples of properties:

Browser.name       // browser name including relevant version
Browser.version    // detailed version info
Browser.DOM        // boolean, true if browser is DOM compatible
Browser.platform   // name of platform/OS
Browser[name]      // boolean , e.g. Browser.IE5, Browser.NS4
Browser[platform]  // boolean , e.g. Browser.WIN , Browser.MAC 

The JSClass/JSC object

JSClass is the root object for all inheritance, and it provides all the necessary methods and properties a class needs to work. JSC is a shorthand reference to the JSClass object.

JSClass 
JSC		
Do not delete or override the JSClass object , as practically all functionality depends on it.


Load Events

To utilize a class, you have to wait until JSC has finished parsing, which usually is once the page has loaded. For this purpose, several load events exist.

JSC.addInitEvent(functionReference1)
JSC.addLoadEvent(function(){
	//code to be executed
})
JSC.addAfterLoadEvent(functionReference3)
JSC.addOnunloadEvent(functionReference4)
Do not override the JavaScript onload nor onunload event , as both are internally used by JSC.

The JSClass onload events are triggered in the following order:

  1. Init
  2. Load
  3. AfterLoad
The difference between these events is conceptual. They should be used for clean separation of functionality: Init for various initialization and configuration, Load for the main code, and AfterLoad for finishing up.

Note that class initialization is best done with static constructors (see "The Static Constructor").

The JSClass onunload event is triggered when exiting or reloading the page.


Classes

Strictly speaking, in JavaScript there is no such thing as a class. However, functions can work as prototypes for objects, in effect mimicking simpler class functionality.

JSClass extends JavaScripts prototype-functionality by parsing functions into classes. This is done through inheritance (see "Inheritance").

First of all, functions need to be correctly named for JSC to recognize them as valid class-canditates.

function TheClass(){} // correct

TheClass=function TheClass(){} // correct, and the safest

TheClass=function(){} //incorrect!!!

TheClass=function(){} 
TheClass.Name="TheClass" // correct
Note that functions with the function name(){} notation are forward referenceable in JavaScript. So the syntax className=function className is the safest , as it eliminates the possibility of forward referencing the function. Beware of mismatching the names though.


The Class Constructor

The class/function works as the class constructor. The constructor is responsible for creating and initializing instances.

TheClass=function TheClass(){ // constructor
  // initializing code
}
TheClass.Extends(JSC)

JSC.addLoadEvent(function(){
  var instance = new TheClass() // instantiating TheClass
})
Note that there is only one constructor per class; there is no way to overload constructors (see "Overloading").

Regular JavaScript syntax is used for instantiating a class.

var instance = new TheClass()
Once an instance is created, there are alternative ways of accessing it (see "UID").


Inheritance

The Extends method is used to inherit/extend a class. The extending class "becomes" a class, and inherits all the instance methods and properties of the extended class.

You can only extend JSClass or subclasses to JSClass. A class that extends JSClass directly, is called a baseclass.

Class1.Extends(JSClass) // baseclass
Class2.Extends(Class1RefOrString) // e.g. string would be "Class1" 
Class3.Extends(Class2RefOrString)
// etc.
It's only possible to pass a classreference as the argument if the class object already exists (e.g. JSClass). Otherwise you pass a string with the name of the class, and the class will be extended when available onload.

As per normal OO inheritance rules, any methods in the extending class override the methods inherited from the parent (see "Super").

Multiple inheritance by extending several classes is (in theory) supported, but it has some inherent issues so it is discouraged at this time. You can however use decorators to achieve similar functionality (see "Decorators").


Super

Super refers to the the extended/parent class constructor or method, depending on the context.

TheClass=function TheClass(x,y){
  Super(x,y) //calls the parent class constructor
}
TheClass.Extends(TheSuperClass)

// AND

TheClass.Public.method=function(){
  Super() // calls the Super method
}
If no Super call exists in a constructor, JSClass inserts an empty Super call as the first statement. Note that a Super call does not need to be the first statement in the constructor.

You can't put Super calls in a method that don't override a superclass method. If you do, you will get an error when using it.

A Super call is not needed nor possible for base classes, i.e. immediate subclasses of JSC.


Packages

Packages are used for grouping relevant classes together. All classes belong to packages, and what package a class belongs to is automatically determined by what folder the class file is in. You use packages to import classes (see "The Import function").

Packages also determine what namespace the class exists in. For every package, a package object with the same name is created. You can always access a class via it's package object.

var obj = new package1.package2.TheClass() //e.g.

The Import function

The Import function is used for downloading classes/JavaScript files.

Import(pathString1,pathString2,...n)
Import("folder/file.js") 
The class path/root folder, is by default the same as for the file including JSClass. You can explicitly set the class path with the setClassPath() method.

Import.setClassPath(classPathString) // e.g. js/classes/
When importing classes, packages are used.

Import(thePackageString)
Import("package1.package2.TheClass") //e.g.
The above example would import 'theClassPath/package1/package2/TheClass.js'.

To import all classes in a package, the syntax is:

Import("thePackage.*")
Since there is no direct way of importing all classes in the package, what actually happens in the above example is that the '_Package.js' file in the package folder is downloaded. In the package file you are free to import whatever classes are needed for the package.

<< _Package.js >>

Import(
  "thePackage.Class1",  
  "thePackage.Class2",
  "thePackage.Class3"
)
Due to security issues in JavaScript, there is no way to ensure that all of the classes imported reside in the package, nor is there an automatic way of keeping the '_Package.js' file up-to-date. That would have to be done manually or with a perl script, for instance.

There is no need for importing classes in any specific order, and classes are imported/downloaded asynchronously if possible. JSC takes care of parsing the classes in the correct order. This means that you can import files directly in classes, thus describing dependencies and guaranteeing the availability of the class.

	
Import("thePackage.OtherClass")

TheClass=function TheClass(arg){ 
  Super(arg)  
}
InlineWindow.Extends("OtherClass") // is guaranteed by the import
JSC keeps track of classes imported, preventing duplicate imports.


Accessors

Encapsulation is available in the form of accessors, which basically have the same meaning as in Java.

Public - accessible everywhere
Protected - accessible to the class and subclasses and classes in the same package

Private was supported in previous versions of JSClass, but is not anymore. The implementation was too complex and substantially degraded performance.

Note that the these accessors are mainly for encouraging proper OO programming. Since everything is public in JavaScript, protected only has semantical meaning . However, a JSC debugger/error module could be used to warn about improper use.

You define methods/properties is in specific accessor objects.

TheClass.Public={ w:12 }
TheClass.Protected={ 
  x:34
}
You access methods/properties either with the this object or directly (which you can't do in normal JavaScript).

TheClass=function TheClass(){
  this.x=3
  y=[] 		// same as this.y=[], y defined outside
  method()		
}

TheClass.Protected={ y:null, method:function(){} }
Note that arrays and object objects must be initialized/created in the constructor. If you were to create them in the accessor object, they would be shared for all instances.

Also note that you can define/create public properties in the constructor directly, by using the this reference. However, to be consistant, you should define them in the Public accessor object.


Static

Static methods and properties are properties that apply to the class itself, instead of a class instance. They are defined in a static accessor object.

TheClass.Static={
  Protected:{
    num:3,
    obj:{}
  },	
  Public:{
    method:function(){}
  }
}
In static methods and the static constructor (see"The Static Constructor"), you can access static methods and properties directly, explicitly or via the Static keyword.

TheClass.Static.Public.method=function(){
  num=4
  TheClass.num=5 // explicit, works everywhere
  Static.num     // works in static/instance methods/constructors
}
Static methods and properties are not inherited nor copied down the inheritance chain and only exist for the defining class. So for all intents and purposes you have to use the explicit notation in subclasses, inner classes and outside the class.

TheClass.method()

The Static Constructor

Static has it's own constructor, which is called automatically onload, before the load events but after all classes have been parsed. It is not inherited nor callable directly.

Other than that, it behaves exactly as a static method.

TheClass.Static=function(){ // should be anonymous function
  method() 
}
TheClass.Static.Protected={
  method:function(){...}
}
The Static constructor provides an easy way of doing class initialization. It can be viewed as a load event for the class itself, as you can instantiate classes in it etc.


Inner Classes

Inner classes are used for coupling of classes: An inner class should not make sense without the enclosing class, and vice versa.

OuterClass=function OuterClass(){  }
OuterClass.Extends(JSC)

OuterClass.InnerClass:function(){ ... }
OuterClass.InnerClass.Extends(JSC)
Note that inner classes in JSClass are static, and are referenced the same way as static methods are.

OuterClass=function OuterClass(){ 
  this.innerInstance = new Static.InnerClass()
  //OR
  this.innerInstance = new OuterClass.InnerClass()
}
Inner classes should reside in the same classfile as the outer class.


Decorators

Decorating a class, means that you add or override existing functionality for an instance or class - without subclassing.

Decorators are quite powerful, enabling easy cross-cutting of functionality that spans across several classes/packages.

For classes, there are two ways to use decorators:

TheClass.Applies(decoratorRefORString)

// OR

TheDecorator.Decorates(classRefORString)
Decorators should be functions, and named the same way as classes.

TheDecorator=function TheDecorator(){}
TheDecorator.Decorates("TheClass") 

TheDecorator.Protected={
  property:null
}
TheDecorator.Public={
  method:function(o){ ... }	
}
TheClass.Applies(TheDecorator)
Class decorators are applied before any classes are parsed by JSClass, so extending a decorated class gives the subclass all of the decorated methods/properties.

Right now decorating decorators is possible, but needs to happen in the correct order, i.e. it's not done asynchronously.

Instances can be decorated using applyDecorator or Decorates.

theInstance.applyDecorator(TheDecorator)
TheDecorator.Decorates(theInstance,anotherInstance,...,n)

Overloading

Method overloading based on argument length or type does not exist in JavaScript. As with constructors you cannot distinguish between same name methods based on their arguments. This is because there is no automatic type checking in JavaScript, so you can pass any amount of arguments of any type to any method/constructor.

In JSClass this also goes for protected/public methods. If you have a public method with the same name as a protected method, the protected method would replace the public one.


Precedence

Variable precedence in methods/constructors is as follows:

  1. this (used implicitly, in direct method/property access)
  2. local variable OR argument
  3. global variable
window.foo=4

TheClass=function TheClass(foo){ // == "bar"  
  foo         // == 9 ... refers to [this.foo] .. NOT the foo argument 
  this.foo    // == 9
  var foo = 0 // will refer to [this.foo] aswell
  foo         // == 0
  this.foo    // == 0
}
TheClass.Public={
  foo:9
}
new TheClass("bar")

	
Higher precedence variables hide lower precedence variables. You can always access instance properties and methods using the this object, and global variables through the window object.


Native Methods

In JSClass terms, native methods are methods that are native to the JavaScript engine, i.e. pre-defined in the Object prototype.

These methods are not all cross-browser, and they are difficult to parse as they are not exposed to JSC directly. The developer must register them manually for them to be parsed:

JSC.addNative("instanceOf")
Two native methods - toString and valueOf , are added by default, as they are cross-browser.

JSC.addNative("instanceOf")

TheClass=function TheClass(){ ... }
TheClass.Public={
  instanceOf:function(){ ... }, 	// will be parsed
  toString:function(){ ... } 	// will be parsed, default native
}

The Class Object

The Class object is a metaclass object which can be used for getting information about the class.

TheClass=function TheClass(){
  var className = Class.name
  var SuperName = Class.Super.name
  var scopeName = Class.Scope.name
  var baseName  = Class.BaseClass.name
}
Super is a reference to the Super Class object.

Scope is a reference the executing code scope Class object. In constructors, class scope refers to the current class. In methods, it refers to the class that originally defined the method.

BaseClass is a reference to the base Class object in the inheritance chain.

There also is a public method for getting the Class object.

instance.getClass() // returns the class reflection object

UID

Each instance gets a UID (unique identifier) on creation. UID:s are integers, and are incremented by 1 for each new instance, starting from 0.

To get the UID you can use the getUID method.

var UID=instance.getUID()
The inherent UID property is accessible also as a copy in constructors, but only in constructors.

TheClass=function TheClass(){
  var id=UID+Class.getName()
}
You can also get an instance reference from it's UID by using the getInstance method.

var instance = JSC.getInstance(number)
You can get a string representation of the instance through the getGlobal method. This string can then be evaluated to a global reference of the instance. This is useful in cases where you can't pass the instance reference directly, such as in setInterval.

var globalInstanceRefString = instance.getGlobal()
To get an array containing all the instances of a class, use the getInstances method.

var instances = instance.getInstances(deep)
// if deep == true then all subclass instances are included

isClass

To check if a non-null variable is an instance of a class (or a superclass), you use the is[Class] property.

obj["is"+className] //  true or undefined
obj.isTheClass // e.g.
if(obj&&obj.isTheClass) //example of fully valid check
An alternative way is using the instanceOf method:

var bool=obj.instanceOf(TheClassRefORString)
Only use instanceOf if you know you have a real class instance, as only those have the method.


Destroy

Deleting an instance won't completely remove all references to it. You can however use the destroy method.

instance.destroy() 
Destroy simply loops through all methods/properties of the instance, setting them to null . The instance then becomes an empty object, but references to it still remain.

The main purpose for destroy is for finalizing (see "Finalize").

You can override the destroy method, and make it more specific. This can be useful to speed up destroying large amounts of rich instances (which have many properties/methods).


Finalize

JavaScript/JSCript has a reference-count garbage collector which is triggered on exiting/reloading a page. For the most part it works fine, but in some cases it performes poorly (such as with references to HTML objects or with circular data structures).

To get around this problem, JSClass allows you to define a static finalize method for every class that needs extra garbage collection. This method is automatically called before exiting/reloading a page (after onunload events).

TheClass.Static={
  Protected:{
    finalize:function(){
      var instances=getInstances()
      for(var i=0;i< instances.length;i++){
        instances[i].destroy()
      }	
    }  
  }
} 
Marking data to be garbage collected is best done by setting it to null. For instances you can automatically do this by calling the destroy method (see "Destroy").

You can use the getInstances method to get an array containing all instances of the class (see "UID"). You can then loop through the instances and clean them up.