DIR : /home/kozerus/public_html/pn/uize/site-source/guides/classes-and-inheritance.simple

/home/kozerus/public_html/pn/uize/site-source/guides

Introduction
	The UIZE JavaScript Framework implements a system for class inheritance that makes subclassing and object-oriented programming possible in JavaScript.

Creating Classes
	UIZE's system for classes and inheritance makes it dead easy to create a class.

	Class features are provided in the =Uize.Class= module. You can create your own class very easily, simply by calling the =subclass= method on the =Uize.Class= base class, as follows...

	..........................................................
	var Rectangle = Uize.Class.subclass ({
		stateProperties:{
			width:{value:10},
			height:{value:10}
		},
		instanceMethods:{
			displayArea:function () {
				alert (this.get ('width') * this.get ('height'));
			}
		}
	});

	var rectangle = Rectangle ();
	rectangle.displayArea ();  // alerts "100"

	var anotherRectangle = Rectangle ({width:5,height:15});
	anotherRectangle.displayArea ();  // alerts "75"
	..........................................................

	Creating Further Subclasses
		All subclasses that inherit from =Uize.Class= get a =subclass= static method, so you can make further subclasses just as easily...

		..........................................................................................
		var Rectangle = Uize.Class.subclass ({
			stateProperties:{
				width:{value:10},
				height:{value:10}
			},
			instanceMethods:{
				displayArea:function () {
					alert (this.get ('width') * this.get ('height'));
				}
			}
		});

		var VerboseRectangle = Uize.Class.subclass ({
			instanceMethods:{
				displayArea:function () {
					var
						width = this.get ('width'),
						height = this.get ('height')
					;
					alert ('The areas is: ' + width * height + ' (' + width + ' x ' + height + ' )');
				}
			}
		});

		var rectangle = Rectangle ();
		rectangle.displayArea ();  // alerts "100"

		var verboseRectangle = VerboseRectangle ({width:5,height:15});
		verboseRectangle.displayArea ();  // alerts "The area is: 75 (5 x 15)"
		..........................................................................................

Creating Instances
	When you create a class that calling the =Uize.Class.subclass= method, either on the =Uize.Class= base class or a subclass of it, creating instances is more convenient than regular classes.

	The "new" Keyword is Optional
		The =Uize.Class= base class implements a novel mechanism for constructors that makes the "new" keyword optional when creating instances.

		Because the =Uize.Class= base class utilizes `the "no new" mechanism`, one can create instances of any =Uize.Class= subclass either using the =new= operator or not. This means that you can use the "new" keyword or not with UIZE classes (as well as your own classes), and the end result will be the same.

		THIS...
		............................
		var myInstance = MyClass ();
		............................

		IS EQUIVALENT TO...
		................................
		var myInstance = new MyClass ();
		................................

		For a detailed discussion of this mechanism and how it works, consult the section [[The "no new" Mechanism]].

	State Replaces Constructor Arguments
		The =Uize.Class= base class standardizes the constructor signature for all classes to an optional object that specifies initial state for a newly created instance.

		EXAMPLE
		................................................
		var rectangle = Rectangle ({width:5,height:15});
		................................................

		This design choice focuses the design of classes on exposing anything that might affect construction through the `state properties system`, leading to better designed class interfaces. Being an object, the initial state object also allows state properties to be specified in any order, as well as allowing initial instance state for any and all properties to be optionally specified with sensible defaulting defined for state properties in the class' implementation. In contrast, the traditional approach to constructor arguments often suffers from increasingly complicated overloading of the constructor function as a class evolves to become richer.

Declaring Features
	For convenience, UIZE provides a few different ways of declaring a class' features to suit different situations.

	Declaring Features During Class Creation
		The most concise form of declaring class features allows the features to be optionally declared in the call to the =subclass= method.

		.......................................
		var MyClass = Uize.Class.subclass ({
			instanceMethods:{
				someInstanceMethod1:function () {
					// do some stuff
				},
				someInstanceMethod2:function () {
					// do some stuff
				}
			},
			staticMethods:{
				someStaticMethod1:function () {
					// do some stuff
				},
				someStaticMethod2:function () {
					// do some stuff
				}
			}
		});
		.......................................

		The =Uize.Class.subclass= method can optionally accept a =featuresByTypeOBJ= parameter, whose value should be a `features declaration object`, where the name of each property should be the name of a `feature type`, and where the value of each property should be an object containing any number of features of that type.

	Using the declare Static Method
		If you already have a reference to a created class and you would like to declare multiple features of different types in a single method call, you can call the =MyClass.declare= static on the class.

		.......................................
		MyClass.declare ({
			instanceMethods:{
				someInstanceMethod1:function () {
					// do some stuff
				},
				someInstanceMethod2:function () {
					// do some stuff
				}
			},
			staticMethods:{
				someStaticMethod1:function () {
					// do some stuff
				},
				someStaticMethod2:function () {
					// do some stuff
				}
			}
		});
		.......................................

	Using the Feature Declaration Methods
		As an alternative to using the =MyClass.declare= static method, you can declare features on a class using the various feature declaration static methods of the class that are inherited from the =Uize.Class= base class.

		- call the =MyClass.instanceMethods= method to declare instance methods
		- call the =MyClass.staticMethods= method to declare static methods
		- call the =MyClass.stateProperties= method to declare state properties
		- more feature declaration methods: =MyClass.instanceProperties=, =MyClass.staticProperties=, etc.

		EXAMPLE
		....................................
		MyClass.instanceMethods ({
			someInstanceMethod1:function () {
				// do some stuff
			},
			someInstanceMethod2:function () {
				// do some stuff
			}
		});

		MyClass.staticMethods ({
			someStaticMethod1:function () {
				// do some stuff
			},
			someStaticMethod2:function () {
				// do some stuff
			}
		});
		....................................

	Modifying the Class Manually
		In addition to the various convenient ways that are provided for declaring class features, you can also declare features by modifying a class manually.

		- assign properties on the class' =prototype= object to define instance methods and/or properties
		- assign properties on the class to define static methods and/or properties

		EXAMPLE
		....................................................
		MyClass.prototype.someInstanceMethod = function () {
			// do some stuff
		};

		MyClass.someStaticMethod = function () {
			// do some stuff
		};
		....................................................

		While this technique is not recommended, you may encounter older UIZE code that uses this technique for declaring class features, since the code may not yet have been updated since the newer approach to feature declaration was introduced.

	Features Declaration Object ~~ featuresByTypeOBJ
		Both the =MyClass.subclass= and =MyClass.declare= static methods accept a =featuresByTypeOBJ= parameter, which allows multiple features of multiple different `feature types` to be specified in a single feature declaration object and, therefore, declared in a single method call.

		Declaring Features by Type When Creating a Class
			The =Uize.Class.subclass= method supports a variation that lets you `create a subclass, declaring multiple features by type` at the time of creating a class, by supplying just a single =featuresByTypeOBJ= parameter.

			EXAMPLE
			....................................
			var MySubclass = MyClass.subclass ({
				alphastructor:function () {
					// implementation here
				},
				omegastructor:function () {
					// implementation here
				},
				staticMethods:{
					staticMethod1:function () {
						// implementation here
					},
					staticMethod2:function () {
						// implementation here
					}
				},
				instanceMethods:{
					instanceMethod1:function () {
						// implementation here
					},
					instanceMethod2:function () {
						// implementation here
					}
				},
				stateProperties:{
					stateProperty1:{
						// property profile
					},
					stateProperty2:{
						// property profile
					}
				}
			});
			....................................

		Declaring Features by Type for an Already Created Class
			One or more features of one or more different `feature types` can be declared for a class after the class has already been created, by calling the =Uize.Class.declare= method on the class and supplying a =featuresByTypeOBJ= parameter.

			EXAMPLE
			.....................................
			var MyClass = Uize.Class.subclass ();

			MyClass.declare ({
				alphastructor:function () {
					// implementation here
				},
				omegastructor:function () {
					// implementation here
				},
				staticMethods:{
					staticMethod1:function () {
						// implementation here
					},
					staticMethod2:function () {
						// implementation here
					}
				},
				instanceMethods:{
					instanceMethod1:function () {
						// implementation here
					},
					instanceMethod2:function () {
						// implementation here
					}
				},
				stateProperties:{
					stateProperty1:{
						// property profile
					},
					stateProperty2:{
						// property profile
					}
				}
			});
			.....................................

		How the Features Declaration Object is Implemented
			The properties of the =featuresByTypeOBJ= object should correspond to the names of the various `feature declaration methods` supported by the class being subclassed.

			When features are specified, categorized by type, in the =featuresByTypeOBJ= parameter, the =Uize.Class.declare= and =Uize.Class.subclass= methods will iterate over the properties of the object, attempting to call a static method of the name of each property encountered, on the class being subclassed, and passing the value of the property as the first parameter of the feature declaration method.

			So, for example, if the =Uize.Service.subclass= method is called to create a service class, and if a =featuresByTypeOBJ= parameter is specified, and if a =serviceMethods= property exists within the =featuresByTypeOBJ= object, then the =Uize.Service.serviceMethods= static method will be called and the value of the =serviceMethods= property from the =featuresByTypeOBJ= object will be passed as the single parameter to the =Uize.Service.serviceMethods= method.

			To illustrate this by example...

			THIS...
			.........................................
			var FileSystem = Uize.Service.subclass ({
				serviceMethods:{
					readFile:{
						async:false
					},
					writeFile:{
						async:false
					},
					getFiles:{
						async:false
					},
					getFolder:{
						async:false
					},
					// etc.
					// etc.
				}
			});
			.........................................

			...IS EQUIVALENT TO...
			..........................................
			var FileSystem = Uize.Service.subclass ();

			FileSystem.serviceMethods ({
				readFile:{
					async:false
				},
				writeFile:{
					async:false
				},
				getFiles:{
					async:false
				},
				getFolder:{
					async:false
				},
				// etc.
				// etc.
			});
			..........................................

		Standard Properties of the Features Declaration Object
			Support for the following standard properties of the `features declaration object` is built into the =Uize.Class= base class...

			- =alphastructor= - lets you declare the `alphastructor` for the class
			- =omegastructor= - lets you declare the `omegastructor` for the class
			- =instanceMethods= - lets you declare one or more `instance methods` for the class
			- =instanceProperties= - lets you declare one or more `instance properties` for the class
			- =staticMethods= - lets you declare one or more `static methods` for the class
			- =staticProperties= - lets you declare one or more `static properties` for the class
			- =stateProperties= - lets you declare one or more `state properties` for instances of the class
			- =dualContextMethods= - lets you declare one or more `dual context methods` for the class
			- =dualContextProperties= - lets you declare one or more `dual context properties` for the class

		More Feature Types for Specific Base Classes
			Because of `how the features declaration object is implemented`, declaring multiple features, categorized by type, inherently supports new feature types introduced in subclasses.

			In addition to the `standard properties of the features declaration object`, certain classes may introduce `class-specific feature types` for which new feature declaration static methods will be introduced. These new feature types will, by design, introduce additional properties that can be specified in the `features declaration object` when declaring features for subclasses of those classes. For more details, see the section `Class-specific Feature Types`.

		Less Conventional Usages
			Because of `how the features declaration object is implemented`, one can also do less conventional things along with declaring features in the =Uize.Class.subclass= and =Uize.Class.declare= methods.

			For example, one can effectively call the =Uize.Class.set= static method to override the initial values of state properties that are inherited from the base class, as shown in the following example...

			INSTEAD OF...
			...............................................................
			var MySliderWidgetSubclass = Uize.Widget.Bar.Slider.subclass ({
				instanceMethods:{
					// instance methods declared here
				},
				stateProperties:{
					// state properties declared here
				}
			});

			MySliderWidgetSubclass.set ({
				minValue:-50,
				maxValue:50
			});
			...............................................................

			USE...
			...............................................................
			var MySliderWidgetSubclass = Uize.Widget.Bar.Slider.subclass ({
				instanceMethods:{
					// instance methods declared here
				},
				stateProperties:{
					// state properties declared here
				},
				set:{
					minValue:-50,
					maxValue:50
				}
			});
			...............................................................

	Feature Declaration Methods
		The =Uize.Class= module provides a number of methods that let you declare instance and/or static features of a class.

		- =Uize.Class.declare= - lets you declare one or more features of one or more different `feature types` for the class
		- =Uize.Class.alphastructor= - lets you declare the `alphastructor` for the class
		- =Uize.Class.omegastructor= - lets you declare the `omegastructor` for the class
		- =Uize.Class.instanceMethods= - lets you declare one or more `instance methods` for the class
		- =Uize.Class.instanceProperties= - lets you declare one or more `instance properties` for the class
		- =Uize.Class.staticMethods= - lets you declare one or more `static methods` for the class
		- =Uize.Class.staticProperties= - lets you declare one or more `static properties` for the class
		- =Uize.Class.dualContextMethods= - lets you declare one or more `dual context methods` for the class
		- =Uize.Class.dualContextProperties= - lets you declare one or more `dual context properties` for the class
		- =Uize.Class.stateProperties= - lets you declare one or more `state properties` for instances of the class

	Declare Private or Public Features
		The `feature declaration methods` can be used either to declare public features or private features.

		In UIZE, there is no fundamental difference between private methods or properties and public methods or properties - it's all in the naming. By convention, private features are named with an "_" (underscore) prefix. This has its pros and cons, but one side effect of this is that either private or public features (or a mixture of both) can be declared using the `feature declaration methods`.

		EXAMPLE
		........................................
		_class.instanceMethods ({
			_privateInstanceMethod1:function () {
				// implementation here
			},
			_privateInstanceMethod2:function () {
				// implementation here
			},
			publicInstanceMethod1:function () {
				// implementation here
			},
			publicInstanceMethod2:function () {
				// implementation here
			}
		});
		........................................

		In the above example, one call to the =Uize.Class.instanceMethods= method is being used to declare the =_privateInstanceMethod1= and =_privateInstanceMethod2= private instance methods, along with the =publicInstanceMethod1= and =publicInstanceMethod2= public instance methods.

		For a more in-depth discussion on implementing private features for a class, consult the section `Private vs. Public`.

	Feature Declarations are Cumulative
		All the `feature declaration methods` can be called as many times as desired, and calling them repeatedly is cumulative in nature.

		This is useful, because it lets you break out declarations into different sections in your code if that makes your code more readable and/or manageable.

		EXAMPLE
		........................................
		// Private Instance Methods
		_class.instanceMethods ({
			_privateInstanceMethod1:function () {
				// implementation here
			},
			_privateInstanceMethod2:function () {
				// implementation here
			}
		});

		// ... ... ... ... ... ... ... ... ...

		// Public Instance Methods
		_class.instanceMethods ({
			publicInstanceMethod1:function () {
				// implementation here
			},
			publicInstanceMethod2:function () {
				// implementation here
			}
		});
		........................................

		In the above example, the =Uize.Class.instanceMethods= method is being called twice - in one section to declare private instance methods, and in the other section to declare public instance methods.

	Dual Context Features
		Dual context class features are features that exist both on the class as well as instances of the class.

		Examples of dual context features are the various event system methods. For example, the =fire= instance method lets you fire an instance event, while the =Uize.Class.fire= static method lets you fire an event on a class. Both the instance and class methods for firing events share the same underlying implementation, where the implementation may contain minor conditionalizing when executing in the instance context versus executing in the class context.

		In cases where it is possible (and possibly even desirable) to share the same function between an instance method and a class method, the =Uize.Class.dualContextMethods= static method can be used to declare such methods in a single statement, rather than separately calling both the =Uize.Class.instanceMethods= and =Uize.Class.staticMethods= methods.

		Although a less likely scenario, it is also possible to declare dual context properties using the =Uize.Class.dualContextProperties= static method. This method is present mainly for symmetry and consistency.

		For dual context features, it is assumed that the feature is named the same on both the instance and the class. In situations where this is not the case, one should just use the separate methods for defining instance features and class features.

Feature Types ~~ Feature Type ~~ Features
	The UIZE class system formally supports the following feature types...

	Alphastructor
		The alphastructor is a constructor in the `alphastructor chain` for a class that is executed before the `state properties` for the instance are initialized.

		When a subclass is created, the `alphastructor chain` for the class is created by copying the alphastructor chain of the superclass and then appending the alphastructor specified for the new subclass.

		The alphastructor can be declared for a class in any of the following ways...

		Declaring the Alphastructor During Subclassing
			The `alphastructor` can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain an =alphastructor= property whose value should be the alphastructor function.

			EXAMPLE
			........................................
			var MyClass = Uize.Class.subclass ({
				alphastructor:function () {
					// implementation of alphastructor
				}
			});
			........................................

		Declaring the Alphastructor After Subclassing, Using MyClass.declare
			The `alphastructor` can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain an =alphastructor= property whose value should be the alphastructor function.

			EXAMPLE
			........................................
			MyClass.declare ({
				alphastructor:function () {
					// implementation of alphastructor
				}
			});
			........................................

		Declaring the Alphastructor After Subclassing, Using MyClass.instanceMethods
			The `alphastructor` can be declared for a class after the class has already been created, by calling the =MyClass.alphastructor= method on the class.

			When calling the =MyClass.alphastructor= method, it should be passed a single function parameter that is the alphastructor function.

			EXAMPLE
			........................................
			MyClass.alphastructor (
				function () {
					// implementation of alphastructor
				}
			);
			........................................

	Omegastructor
		The omegastructor is a constructor in the `omegastructor chain` for a class that is executed after the `state properties` for the instance are initialized.

		When a subclass is created, the `omegastructor chain` for the class is created by copying the omegastructor chain of the superclass and then appending the omegastructor specified for the new subclass.

		The omegastructor can be declared for a class in any of the following ways...

		Declaring the Omegastructor During Subclassing
			The `omegastructor` can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain an =omegastructor= property whose value should be the omegastructor function.

			EXAMPLE
			........................................
			var MyClass = Uize.Class.subclass ({
				omegastructor:function () {
					// implementation of omegastructor
				}
			});
			........................................

		Declaring the Omegastructor After Subclassing, Using MyClass.declare
			The `omegastructor` can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain an =omegastructor= property whose value should be the omegastructor function.

			EXAMPLE
			........................................
			MyClass.declare ({
				omegastructor:function () {
					// implementation of omegastructor
				}
			});
			........................................

		Declaring the Omegastructor After Subclassing, Using MyClass.instanceMethods
			The `omegastructor` can be declared for a class after the class has already been created, by calling the =MyClass.omegastructor= method on the class.

			When calling the =MyClass.omegastructor= method, it should be passed a single function parameter that is the omegastructor function.

			EXAMPLE
			........................................
			MyClass.omegastructor (
				function () {
					// implementation of omegastructor
				}
			);
			........................................

	Instance Methods
		Instance methods are functions that are assigned on the =prototype= object of a class.

		When a subclass is created, all instance methods of the superclass are inherited by the subclass through a copy operation. Once a subclass is created, changing the inherited instance methods on the superclass has no effect on the subclass.

		Instance methods can be declared for a class in any of the following ways...

		Declaring Instance Methods During Subclassing
			Instance methods can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain an =instanceMethods= property whose value should be an object containing mappings of instance method names to implementation functions.

			EXAMPLE
			.................................................
			var MyClass = Uize.Class.subclass ({
				instanceMethods:{
					foo:function () {
						// implementation of foo instance method
					},
					bar:function () {
						// implementation of bar instance method
					}
				}
			});
			.................................................

		Declaring Instance Methods After Subclassing, Using MyClass.declare
			Instance methods can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain an =instanceMethods= property whose value should be an object containing mappings of instance method names to implementation functions.

			EXAMPLE
			.................................................
			MyClass.declare ({
				instanceMethods:{
					foo:function () {
						// implementation of foo instance method
					},
					bar:function () {
						// implementation of bar instance method
					}
				}
			});
			.................................................

		Declaring Instance Methods After Subclassing, Using MyClass.instanceMethods
			Instance methods can be declared for a class after the class has already been created, by calling the =MyClass.instanceMethods= method on the class.

			When calling the =MyClass.instanceMethods= method, an instance methods declaration object should be provided, containing mappings of instance method names to implementation functions.

			EXAMPLE
			..............................................
			MyClass.instanceMethods ({
				foo:function () {
					// implementation of foo instance method
				},
				bar:function () {
					// implementation of bar instance method
				}
			});
			..............................................

	Instance Properties
		Instance properties are non-function type values that are assigned on the =prototype= object of a class.

		When a subclass is created, all instance properties of the superclass are inherited by the subclass through a clone-copy operation. Once a subclass is created, changing the inherited instance properties on the superclass has no effect on the subclass.

		Instance properties can be declared for a class in any of the following ways...

		Declaring Instance Properties During Subclassing
			Instance properties can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain an =instanceProperties= property whose value should be an object containing mappings of instance property names to initial values.

			EXAMPLE
			....................................
			var MyClass = Uize.Class.subclass ({
				instanceProperties:{
					foo:'bar',
					baz:'qux'
				}
			});
			....................................

		Declaring Instance Properties After Subclassing, Using MyClass.declare
			Instance properties can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain an =instanceProperties= property whose value should be an object containing mappings of instance property names to initial values.

			EXAMPLE
			.......................
			MyClass.declare ({
				instanceProperties:{
					foo:'bar',
					baz:'qux'
				}
			});
			.......................

		Declaring Instance Properties After Subclassing, Using MyClass.instanceProperties
			Instance properties can be declared for a class after the class has already been created, by calling the =MyClass.instanceProperties= method on the class.

			When calling the =MyClass.instanceProperties= method, an instance properties declaration object should be provided, containing mappings of instance property names to initial values.

			EXAMPLE
			.............................
			MyClass.instanceProperties ({
				foo:'bar',
				baz:'qux'
			});
			.............................

	Static Methods
		Static methods are functions that are assigned on the class.

		When a subclass is created, all static methods of the superclass are inherited by the subclass through a copy operation (the exception to this is `non-inheritable statics` that are registered with `the MyClass.nonInheritableStatics static property`). Once a subclass is created, changing the inherited static methods on the superclass has no effect on the subclass.

		Static methods can be declared for a class in any of the following ways...

		Declaring Static Methods During Subclassing
			Static methods can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain an =staticMethods= property whose value should be an object containing mappings of static method names to implementation functions.

			EXAMPLE
			...............................................
			var MyClass = Uize.Class.subclass ({
				staticMethods:{
					foo:function () {
						// implementation of foo static method
					},
					bar:function () {
						// implementation of bar static method
					}
				}
			});
			...............................................

		Declaring Static Methods After Subclassing, Using MyClass.declare
			Static methods can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain an =staticMethods= property whose value should be an object containing mappings of static method names to implementation functions.

			EXAMPLE
			...............................................
			MyClass.declare ({
				staticMethods:{
					foo:function () {
						// implementation of foo static method
					},
					bar:function () {
						// implementation of bar static method
					}
				}
			});
			...............................................

		Declaring Static Methods After Subclassing, Using MyClass.instanceMethods
			Static methods can be declared for a class after the class has already been created, by calling the =MyClass.staticMethods= method on the class.

			When calling the =MyClass.staticMethods= method, a static methods declaration object should be provided, containing mappings of static method names to implementation functions.

			EXAMPLE
			............................................
			MyClass.staticMethods ({
				foo:function () {
					// implementation of foo static method
				},
				bar:function () {
					// implementation of bar static method
				}
			});
			............................................

	Static Properties
		Static properties are non-function type values that are assigned on the class.

		When a subclass is created, all static properties of the superclass are inherited by the subclass through a clone-copy operation (the exception to this is `non-inheritable statics` that are registered with `the MyClass.nonInheritableStatics static property`). Once a subclass is created, changing the inherited static properties on the superclass has no effect on the subclass.

		Static properties can be declared for a class in any of the following ways...

		Declaring Static Properties During Subclassing
			Static properties can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain a =staticProperties= property whose value should be an object containing mappings of static property names to initial values.

			EXAMPLE
			....................................
			var MyClass = Uize.Class.subclass ({
				staticProperties:{
					foo:'bar',
					baz:'qux'
				}
			});
			....................................

		Declaring Static Properties After Subclassing, Using MyClass.declare
			Static properties can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain a =staticProperties= property whose value should be an object containing mappings of static property names to initial values.

			EXAMPLE
			.....................
			MyClass.declare ({
				staticProperties:{
					foo:'bar',
					baz:'qux'
				}
			});
			.....................

		Declaring Static Properties After Subclassing, Using MyClass.staticProperties
			Static properties can be declared for a class after the class has already been created, by calling the =MyClass.staticProperties= method on the class.

			When calling the =MyClass.staticProperties= method, a static properties declaration object should be provided, containing mappings of static property names to initial values.

			EXAMPLE
			...........................
			MyClass.staticProperties ({
				foo:'bar',
				baz:'qux'
			});
			...........................

	State Properties
		State properties are instance properties with special features that, among other things, ties them into the event system so that changes in their values can be easily observed.

		When a subclass is created, all state properties of the superclass are inherited by the subclass through a clone-copy operation. Once a subclass is created, changing the inherited state properties on the superclass has no effect on the subclass. For a detailed discussion of state properties and the various features supported for them, consult the [[state-properties.html][State Properties guide]].

		State properties can be declared for a class in any of the following ways...

		Declaring State Properties During Subclassing
			State properties can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain a =stateProperties= property whose value should be an object containing mappings of state property names to property profiles.

			EXAMPLE
			.........................................................................
			var MyClass = Uize.Class.subclass ({
				stateProperties:{
					width:{
						conformer:function (value) {return Uize.constrain (value,1,50)},
						value:10
					},
					height:{
						conformer:function (value) {return Uize.constrain (value,1,50)},
						value:10
					}
				}
			});
			.........................................................................

		Declaring State Properties After Subclassing, Using MyClass.declare
			State properties can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain a =stateProperties= property whose value should be an object containing mappings of state property names to property profiles.

			EXAMPLE
			.........................................................................
			MyClass.declare ({
				stateProperties:{
					width:{
						conformer:function (value) {return Uize.constrain (value,1,50)},
						value:10
					},
					height:{
						conformer:function (value) {return Uize.constrain (value,1,50)},
						value:10
					}
				}
			});
			.........................................................................

		Declaring State Properties After Subclassing, Using MyClass.instanceProperties
			State properties can be declared for a class after the class has already been created, by calling the =MyClass.stateProperties= method on the class.

			When calling the =MyClass.stateProperties= method, a state properties declaration object should be provided, containing mappings of state property names to property profiles.

			EXAMPLE
			......................................................................
			MyClass.stateProperties ({
				width:{
					conformer:function (value) {return Uize.constrain (value,1,50)},
					value:10
				},
				height:{
					conformer:function (value) {return Uize.constrain (value,1,50)},
					value:10
				}
			});
			......................................................................

	Dual Context Methods
		Dual context methods are functions that are assigned on the class as well as on the =prototype= object of the class.

		Because dual context methods are essentially just combined static and instance methods, all dual context methods of a superclass are inherited by a subclass through the copy operations used when inheriting static and instance methods. The exception to this is a dual context method where the static method is registered with `the MyClass.nonInheritableStatics static property` as being a `non-inheritable static`. Once a subclass is created, changing the inherited dual context methods on the superclass has no effect on the subclass.

		Dual context methods can be declared for a class in any of the following ways...

		Declaring Dual Context Methods During Subclassing
			Dual context methods can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain an =dualContextMethods= property whose value should be an object containing mappings of dual context method names to implementation functions.

			EXAMPLE
			.....................................................
			var MyClass = Uize.Class.subclass ({
				dualContextMethods:{
					foo:function () {
						// implementation of foo dual context method
					},
					bar:function () {
						// implementation of bar dual context method
					}
				}
			});
			.....................................................

		Declaring Dual Context Methods After Subclassing, Using MyClass.declare
			Dual context methods can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain an =dualContextMethods= property whose value should be an object containing mappings of dual context method names to implementation functions.

			EXAMPLE
			.....................................................
			MyClass.declare ({
				dualContextMethods:{
					foo:function () {
						// implementation of foo dual context method
					},
					bar:function () {
						// implementation of bar dual context method
					}
				}
			});
			.....................................................

		Declaring Dual Context Methods After Subclassing, Using MyClass.dualContextMethods
			Dual context methods can be declared for a class after the class has already been created, by calling the =MyClass.dualContextMethods= method on the class.

			When calling the =MyClass.dualContextMethods= method, a dual context methods declaration object should be provided, containing mappings of dual context method names to implementation functions.

			EXAMPLE
			..................................................
			MyClass.dualContextMethods ({
				foo:function () {
					// implementation of foo dual context method
				},
				bar:function () {
					// implementation of foo dual context method
				}
			});
			..................................................

	Dual Context Properties
		Dual context properties are non-function type values that are assigned on the class as well as on the =prototype= object of the class.

		Because dual context properties are essentially just combined static and instance properties, all dual context properties of a superclass are inherited by a subclass through the clone-copy operations used when inheriting static and instance properties. The exception to this is a dual context property where the static property is registered with `the MyClass.nonInheritableStatics static property` as being a `non-inheritable static`. Once a subclass is created, changing the inherited dual context properties on the superclass has no effect on the subclass.

		Dual context properties can be declared for a class in any of the following ways...

		Declaring Dual Context Properties During Subclassing
			Dual context properties can be declared for a class when the class is created, by using the optional =featuresByTypeOBJ= parameter when calling the =Uize.Class.subclass= static method.

			The `features declaration object` should contain an =dualContextProperties= property whose value should be an object containing mappings of dual context property names to initial values.

			EXAMPLE
			....................................
			var MyClass = Uize.Class.subclass ({
				dualContextProperties:{
					foo:'bar',
					baz:'qux'
				}
			});
			....................................

		Declaring Dual Context Properties After Subclassing, Using MyClass.declare
			Dual context properties can be declared for a class after the class has already been created, by calling the =MyClass.declare= method on the class.

			The `features declaration object` passed to the =MyClass.declare= method should contain an =dualContextProperties= property whose value should be an object containing mappings of dual context property names to initial values.

			EXAMPLE
			..........................
			MyClass.declare ({
				dualContextProperties:{
					foo:'bar',
					baz:'qux'
				}
			});
			..........................

		Declaring Dual Context Properties After Subclassing, Using MyClass.dualContextProperties
			Dual context properties can be declared for a class after the class has already been created, by calling the =MyClass.dualContextProperties= method on the class.

			When calling the =MyClass.dualContextProperties= method, a dual context properties declaration object should be provided, containing mappings of dual context property names to initial values.

			EXAMPLE
			................................
			MyClass.dualContextProperties ({
				foo:'bar',
				baz:'qux'
			});
			................................

Class-specific Feature Types
	In addition to the standard `feature types` that are built into the =Uize.Class= base class, any class can introduce new class-specific feature types for which new feature declaration static methods will be introduced to allow features of those new types to be declared by subclasses of the class.

	Service Methods, as an Example
		For instance, the =Uize.Service= base class introduces the feature type of a service method and provides the =Uize.Service.serviceMethods= static method for declaring service methods.

		So, inherently, service methods can be declared in the =featuresByTypeOBJ= parameter along with other feature types that were introduced in the =Uize.Class= base class (`instance methods`, `instance properties`, `static methods`, `static properties`, `state properties`, etc.), simply by specifying a =serviceMethods= property in the =featuresByTypeOBJ= object.

	Your Own Feature Types
		You can introduce your own new feature types, and these feature types will get the benefits of the generalized system for declaring features

		Quite simply, if you implement a new base class of which multiple different subclasses will be created, and you define a static method that allows developers to declare features of a new feature type that is introduced in your base class, then features of that type can be declared in the =Uize.Class.subclass= and =Uize.Class.declare= methods.

		Consider the following example...

		EXAMPLE
		.........................................................................
		var ClassWithStateMonitors = Uize.Class.subclass ({
			staticMethods:{
				stateMonitors:function (monitorsByProperty) {
					for (var property in monitorsByProperty) {
						var monitor = monitorsByProperty [property];
						// code to register monitor for state property
					}
				}
			}
		});

		var Rectangle = ClassWithStateMonitors.subclass ({
			stateProperties:{
				width:{
					conformer:function (value) {return Uize.constrain (value,1,50)},
					value:10
				},
				height:{
					conformer:function (value) {return Uize.constrain (value,1,50)},
					value:10
				}
			},
			stateMonitors:{
				width:function () {
					// monitoring code for width state property
				},
				height:function () {
					// monitoring code for height state property
				}
			}
		});
		.........................................................................

		In the above, very hypothetical example, the class =ClassWithStateMonitors= is being created and a =stateMonitors= static method is declared for it. This method is a feature declaration method for a new "state monitor" feature type. Nevermind what this feature does - it's a hypothetical example, after all.

		Now, given this new =ClassWithStateMonitors= class, we can now create subclasses by calling =ClassWithStateMonitors.subclass=, and for any subclasses of it that we create, we can declare any number of "state monitor" type features by specifying a =stateMonitors= property in the =featuresByTypeOBJ= parameter that is passed to the =ClassWithStateMonitors.subclass= method.

		In our hypothetical =Rectangle= subclass, we're declaring "state monitors" for the =width= and =height= state properties. Once again, let's not worry about what this mysterious "state monitor" feature does - the point is that we've created a new feature type at a particular class in the class hierarchy, and all classes that descend from that class can now declare features of that new type.

		For concrete examples of `class-specific feature types`, you can refer to the =Uize.Service= and =Uize.Widget.V2= classes. The =Uize.Service= class introduces a =serviceMethods= feature type for the benefit of its subclasses, while the =Uize.Widget.V2= class introduces the =cssBindings= and =htmlBindings= feature types.

Constructor Mechanism
	When an instance of a UIZE class is created, construction involves three phases: the =alphastructor= phase, the state property initialization phase, and the =omegastructor= phase.

	### The "no new" Mechanism
		.

	### No Constructor Arguments, in the Traditional Sense
		.

	### Two Phase Construction
		.

	Alphastructor
		The alphastructor is a function that is executed before the state properties for an instance are initialized, and before the =omegastructor= function is executed.

		An alphastructor is declared by specifying a value for the =alphastructor= property of the feature declaration object when calling the superclass' =subclass= method.

		EXAMPLE
		....................................
		var MyClass = Uize.Class.subclass ({
			alphastructor:function () {
				this._someArray = [];
			}
		});
		....................................

		Code inside the alphastructor can set up private "scaffolding" type properties that need to be already in existence by the time any of the state properties are initialized. This allows =onChange= handlers for the state properties to count on certain foundation having been built.

		Because of when it is executed, code inside the alphastructor function cannot rely on the instance's state properties being initialized to the values passed to the constructor.

		EXAMPLE
		......................................
		var
			MyClass = Uize.Class.subclass ({
				alphastructor:function () {
					alert (this.get ('foo'));
				}
			}),
			myClass = new MyClass ({foo:'bar'})
		;
		......................................

		In this example, when the new instance of =MyClass= is created with the value ='bar'= specified for its =foo= state property, the alert inside the alphastructor will display the value =undefined=. This is by design and is an important nuance to take note of.

		Alphastructor Chain
			.

	Omegastructor
		The =omegastructor= is a function that is executed after the =alphastructor= function is executed, and after the state properties for an instance are initialized.

		Omegastructor Chain
			.

	### Constructors are Cumulative
		.

Inheritance
	The =Uize.Class= base class provides a mechanism for inheriting `features` declared for the class being subclassed, including the `alphastructor`, `omegastructor`, `static methods`, `static properties`, `instance methods`, `instance properties`, `state properties`, etc.

	The inheritance system that is implemented in the =Uize.Class= base class overcomes some of the weaknesses of a superficial prototype-based approach to inheritance.

	### What Gets Inherited
		.

	### Constructors are Cumulative
		.

	Overriding Inherited Features
		Features that are inherited from a superclass can be overridden in exactly the same way as they are declared.

		Overriding Instance Methods and Properties
			Overriding instance methods and properties of a superclass is easy. It's just a matter of re-assigning.

			EXAMPLE
			...................................................................................................
			var MyClass = Uize.Class.subclass ({      // create a class with an instance method
				instanceMethods:{
					foo:function () {alert ('bar')}
				}
			});

			var MySubclass = MyClass.subclass ({      // create subclass and override inherited instance method
				instanceMethods:{
					foo:function () {
						alert ('foo');
						MyClass.doMy (this,'foo');  // call superclass' version of foo instance method
					}
				}
			});

			var myClassInstance = new MyClass;        // create an instance of the class
			myClassInstance.foo ();                   // call foo method on instance of class

			var mySubclassInstance = new MySubclass;  // create an instance of the subclass
			mySubclassInstance.foo ();                // call foo method on instance of subclass
			...................................................................................................

			In this example, the =foo= instance method of the subclass has been overrided so that it first alerts the text "foo" and then calls the =foo= method implementation from the superclass and alerts the text "bar".

			Typically, the code that implements the methods of a subclass is near (or in the same scope as) the code that creates the subclass, so the subclass knows its superclass. When you start digging into subclass modules, you will encounter this reference to the superclass in the form of the =_superclass= variable (named such by convention).

		Overriding Static Methods and Properties
			Overriding static methods and properties of a superclass is easy. It's just a matter of re-assigning.

			EXAMPLE
			............................................................................................
			var MyClass = Uize.Class.subclass ({  // create a class with a static method
				staticMethods:{
					myStaticMethod:function () {alert ('foo')}
				}
			});

			var MySubclass = MyClass.subclass ({  // create subclass, overriding inherited static method
				staticMethods:{
					myStaticMethod:function () {alert ('bar')}
				}
			});

			myClass.myStaticMethod ();            // call myStaticMethod on MyClass
			mySubclass.myStaticMethod ();         // call myStaticMethod on MySubclass
			............................................................................................

			In this example, =MySubclass= is a subclass of =MyClass=, and both classes have a static method =myStaticMethod=. By subclassing =MyClass=, =MySubclass= inherits the implementation of =myStaticMethod= from =MyClass=. Re-assigning the =myStaticMethod= property of =MySubclass= overrides the inherited implementation without affecting =MyClass=. So, calling =myStaticMethod= on =MyClass= will product the text "foo" in an alert dialog, while calling =myStaticMethod= on =MySubclass= will product the text "bar" in an alert dialog.

			Calling a Subclass Version of a Static Method
				One may implement a class in such a way that a static method is intended to be overrided by a subclass. And in such cases, one may also wish the superclass' implementation to be guaranteed to always use the subclass' version of the static method.

				Calling a subclass' version of a static method can be done in two ways, depending on whether the code is in the implementation for an instance method or for a static method of the superclass.

				The Instance Method Case
					Within an instance method's implementation, one can use the =Class= instance property to reference the actual class of the instance - even in the superclass' code - as in...

					.......................................................................................
					var MyClass = Uize.Class.subclass ({
						instanceMethods:{
							myInstanceMethod:function () {
								this.Class.myStaticMethod (); // call myStaticMethod static method on subclass
							}
						}
					});
					.......................................................................................

					Now, in the case of an instance of =MyClass=, the =myStaticMethod= static method will be called on =MyClass=. However, in the case of an instance of =MySubclass= (that is a subclass of =MyClass=), the =myStaticMethod= static method will be called on =MySubclass=, even though the =myInstanceMethod= instance method is implemented by =MyClass=. If =MySubclass= didn't override the implementation inherited from =MyClass=, then there will be no difference in the outcome.

					Let's take a look at an example...

					EXAMPLE
					.........................................................................................
					var MyClass = Uize.Class.subclass ({      // create a class
						staticMethods:{
							myStaticMethod:function () {
								alert ('MyClass');
							}
						},
						instanceMethods:{
							myInstanceMethod:function () {
								this.Class.myStaticMethod ();
							}
						}
					});

					var MySubclass = MyClass.subclass ({      // subclass the class, overriding static method
						staticMethods:{
							myStaticMethod:function () {
								alert ('MySubclass');
							}
						}
					});

					var mySubclassInstance = new MySubclass;  // create instance of MySubclass
					mySubclassInstance.myInstanceMethod ();   // call myInstanceMethod
					.........................................................................................

					In this example, =MyClass= implements the static method =MyClass.myStaticMethod=. Now, =MySubclass= overrides the implementation of =myStaticMethod= inherited from =MyClass=. The implementation of =myInstanceMethod= (inherited from =MyClass=) uses the =Class= property to get a reference to the actual class of an instance on which the method is being called. So, when this method is called on the instance of =MySubclass= named =mySubclassInstance=, the overrided form of =myStaticMethod= (implemented by =MySubclass=) is called, resulting in the text "MySubclass" being displayed in the alert dialog - *not* the text "MyClass".

				The Static Method Case
					Within a static method's implementation, one can use the =this= keyword to reference the actual class - even in the superclass' code - as in...

					......................................
					MyClass.myStaticMethod = function () {
						this.myOtherStaticMethod ();
					};
					......................................

					Let's take a look at an example...

					EXAMPLE
					...............................................................................................
					MyClass = Uize.Class.subclass ({         // create a class with two static methods
						staticMethods:{
							myStaticMethod:function () {
								this.myOtherStaticMethod ();
							},
							myOtherStaticMethod:function () {
								alert ('MyClass');
							}
						}
					});

					MySubclass = MyClass.subclass ({         // create subclass, overriding inherited static method
						staticMethods:{
							myOtherStaticMethod:function () {
								alert ('MySubclass');
							}
						}
					});

					MySubclass.myStaticMethod ();            // call inherited static method
					...............................................................................................

					In this example, =MyClass= implements the two static methods =MyClass.myStaticMethod= and =MyClass.myOtherStaticMethod=. The implementation of =MyClass.myStaticMethod= wants to always call the subclass' version of =myOtherStaticMethod=. So, instead of calling it as =MyClass.myOtherStaticMethod ()=, it calls it as =this.myOtherStaticMethod ()=.

					Now, if =myStaticMethod= is called on =MyClass=, then =this= will be a reference to =MyClass=. However, if =myStaticMethod= is called on =MySubclass=, then =this= will be a reference to =MySubclass=. Consequently, using =this= guarantees that the subclass' version will be called. In this example, =MySubclass= overrides the implementation of =myOtherStaticMethod= inherited from =MyClass=, so the statement =MySubclass.myStaticMethod ()= will result in the text "MySubclass" being displayed in the alert dialog - *not* the text "MyClass".

		Overriding State Property Values
			The initial value for a state property inherited from a superclass can be overrided by calling the =MyClass.set= static method that is inherited from the =Uize.Class= base class.

			The initial value for a state property is declared by specifying the =value= property in the profile for the state property, as follows...

			EXAMPLE
			..................................................................................
			var MyClass = Uize.Class.subclass ({   // create a class with a foo state property
				stateProperties:{
					_foo:{
						name:'foo',
						onChange:function () {
							// code to handle a change in foo's value
						},
						value:'bar'
					}
				}
			});

			var _myClassInstance = new MyClass;    // create instance of MyClass
			alert (_myClassInstance.get ('foo'));  // alert value of foo state property
			..................................................................................

			In the above example, the text "bar" will be displayed in the alert dialog.

			Now, the initial value for the =foo= state property inherited from =MyClass= can be overrided in a subclass, as follows...

			EXAMPLE
			..............................................................................................
			var MyClass = Uize.Class.subclass ({   // create a class with a foo state property
				stateProperties:{
					_foo:{
						name:'foo',
						onChange:function () {
							// code to handle a change in foo's value
						},
						value:'bar'
					}
				}
			});

			var MySubclass = MyClass.subclass ({   // subclass the class, overriding initial value for foo
				set:{foo:'NOT BAR'}
			});

			var _mySubclassInstance = new MySubclass;  // create instance of MySubclass
			alert (_mySubclassInstance.get ('foo'));   // alert value of foo state property
			..............................................................................................

			In this example, we have now created a subclass of =MyClass= named =MySubclass=. The new subclass inherits the =foo= state property, along with its initial value of ='bar'= that is declared in =MyClass=. When creating the =MySubclass= subclass, we use the =set= declaration to change the initial value of this state property to ='NOT BAR'=. This is equivalent to calling =MySubclass.set=, but we can tuck it neatly into the subclassing statement. Now, the fresh instance of =MySubclass= that is created, named =_mySubclassInstance=, will have the initial value ='NOT BAR'= for its =foo= state property, and the alert dialog will display this text.

	### Inheriting State Properties
		State properties declared for a class are inherited when creating a subclass.

		EXAMPLE
		..........................................................................
		var MyClass = Uize.Class.subclass ();  // create a class
		MyClass.stateProperties ({             // declare the "foo" state property
			_foo:{
				name:'foo',
				onChange:function () {
					// code to handle a change in foo's value
				},
				value:'initial value for foo'
			}
		});

		var MySubclass = MyClass.subclass ();  // create a subclass
		MySubclass.stateProperties ({          // declare the "bar" state property
			_bar:{
				name:'bar',
				onChange:function () {
					// code to handle a change in bar's value
				},
				value:'initial value for bar'
			}
		});
		..........................................................................

		After the above code has executed, the class =MySubclass= will have the two state properties =foo= and =bar=.

	Features that All Classes Inherit
		As part of the foundation for developing classes in UIZE, the =Uize.Class= base class provides its subclasses with numerous inherited systems, such as the `event system`, `state properties system`, `instance creation system`, `subclassing system`, and `conditions and derivations`.

		###
			Event System
				.

			State Properties System
				.

				- briefly mention Changed events

			Instance Creation System
				The "no new" Mechanism
				state properties initialization

			Subclassing System
				- create a subclass
				- declare feature and/or override inherited features

			Conditions and Derivations
				.

				ties events and state properties together

Advanced Topics
	Private vs. Public
		By convention, private methods and properties - both instance and static - are distinguished from public methods and properties by prefixing their names with an underscore.

		EXAMPLE
		........................................................................
		var MyClass = Uize.Class.subclass ({
			instanceMethods:{
				_myPrivateInstanceMethod:function () {  // private instance method
					// do stuff
				},
				myPublicInstanceMethod:function () {    // public instance method
					// do stuff
				}
			},

			staticMethods:{
				_myPrivateStaticMethod:function () {    // private static method
					// do stuff
				},
				myPublicStaticMethod:function () {      // public static method
					// do stuff
				}
			}
		});
		........................................................................

		Technically, such private methods and properties are not thoroughly private and can be accessed as public methods or properties. However, because their names will be changed by the Scruncher when the code is scrunched to minimize its size, one cannot reliably access these methods and properties. This is a kind of "soft privacy".

		IMPORTANT

		When creating subclasses, it is important not to access methods or properties defined in the superclass with private names. The code will work when it is unscrunched, but there is no guarantee *what* your subclass will be accessing when all the code is scrunched.

	Non-inheritable Statics ~~ Non-inheritable Static
		Unless otherwise specified, all static features - methods as well as properties - of a =Uize.Class= subclass are inherited in turn by their subclasses.

		There are times, however, when there is no compelling reason for a static feature of a class to be inherited by its subclasses. In fact, in some cases too many inherited static features can just clutter subclasses in the class hierarchy with cruft that they neither need nor care about. In such cases, the inheritance system of the UIZE JavaScript Framework provides a way to "register" static features of a class as being non-inheritable. This is done using the =MyClass.nonInheritableStatics= static property.

		The MyClass.nonInheritableStatics Static Property
			The =MyClass.nonInheritableStatics= static property is a lookup object, automatically created for a class, in which you can register the static features (methods or properties) of the class that should *not* be inherited when that class is subclassed.

			Each property of the =MyClass.nonInheritableStatics= lookup object represents a single static feature of the class that should not be inherited by subclasses, where the name of each property should be the name of a static feature (excluding the module name), and the value of each property should be a truthy value (such as =true=, =1=, ='foo'=, =[]=, ={}=, etc.). After a class has been created, non-inheritable statics can be registered for that class by assigning properties to the class' =MyClass.nonInheritableStatics= static property, as shown in the example below...

			EXAMPLE
			...........................................................................
			MyClass = Uize.Class.subclass ({
				staticMethods:{
					someUtilityFunction:function () {
						// do something of great utility
					}
				}
			});
			MyClass.nonInheritableStatics.someUtilityFunction = 1;

			MyClassSubclass = MyClass.subclass ();
			alert (MyClassSubclass.someUtilityFunction); // alerts the text "undefined"
			...........................................................................

			In the above example, the =MyClass.someUtilityFunction= static method of the class =MyClass= has been registered as a non-inheritable static. This is done by the statement =MyClass.nonInheritableStatics.someUtilityFunction = 1=. Now, when the =MyClassSubclass= class is created by calling the =MyClass.subclass= method, the new subclass that is created does not get the =someUtilityFunction= static feature. Therefore, the =alert= statement displays the text "undefined" in the alert dialog.

			nonInheritableStatics is a Non-inheritable Static
				When a class is created, the =MyClass.nonInheritableStatics= static property is automatically initialized on that class to a fresh object with the value ={nonInheritableStatics:1}=.

				This initial mapping means that the =MyClass.nonInheritableStatics= static property is, itself, not inheritable by subclasses - subclasses get their own fresh object. So, in our example, when the =MyClassSubclass= subclass is created, its fresh =MyClassSubclass.nonInheritableStatics= property does *not* have an entry for the =someUtilityFunction= static feature, because it does not have that static feature and the contents of the =MyClass.someUtilityFunction= object is not inherited by the =MyClassSubclass= class.

		All Types of Statics Can Be Non-inheritable
			All types of static features of a class can be registered as non-inheritable - methods as well as properties.

			Registering static properties as non-inheritable is accomplished in the same way as for static methods. Consider the following example...

			EXAMPLE
			..........................................................................
			MyClass = Uize.Class.subclass ({
				staticProperties:{
					someStaticProperty:'foo'
				}
			});
			MyClass.nonInheritableStatics.someStaticProperty = 1;

			MyClassSubclass = MyClass.subclass ();
			alert (MyClassSubclass.someStaticProperty); // alerts the text "undefined"
			..........................................................................

			In the above example, the alert dialog would display the text "undefined", because the =MyClass.someStaticProperty= static property of the class =MyClass= has been registered as non-inheritable, so it is not inherited by the =MyClassSubclass= class that is created by subclassing =MyClass=.

		Utility Functions Need Not Be Inheritable
			A good case for making a static method non-inheritable is if it is really just a utility function that happens to be stashed in a class' namespace.

			Static methods that are really just utility or helper functions don't care about the context on which they are called. They just happen to be called on a class as a context because they are assigned as properties on a class.

			Take, for example, the =Uize.Fade.celeration= static method of the =Uize.Fade= class. You may be calling it on the =Uize.Fade= context, but this utility function's implementation doesn't even reference the =this= keyword - it just doesn't care about the context on which it is called. You could, in fact, assign this static method to a local variable and then call it using that local variable, and it would behave in just the same way as if it were being called on the class. Consider the following example...

			EXAMPLE
			..........................................................
			var celeration = Uize.Fade.celeration;
			alert (celeration (.5,.5) (.3));  // alerts the text ".18"
			..........................................................

			In the above example, our local variable =celeration= is a function reference. When that local variable is used to call the function in order to generate an acceleration/deceleration curve function, everything works just fine. The =alert= statement alerts the result of calling the generated curve function with the progress amount of =.3=, yielding the curve-adjusted blend amount of =.18=. Because the =Uize.Fade.celeration= static method doesn't operate on a =Uize.Fade= subclass or need a =Uize.Fade= subclass as its context when it is called, there's no compelling reason for it to be inheritable, and so it is not.

		When Statics Should Be Inheritable
			Whenever a static method or property is intended to be unique to its class context, and it is also desirable for that method or property to be inherited by subclasses, then it should *not* be registered as non-inheritable.

			Examples of some static methods in the =Uize.Class= base class that are inheritable are the =Uize.Class.set=, =Uize.Class.get=, =Uize.Class.toggle=, =Uize.Class.fire=, =Uize.Class.wire=, =Uize.Class.subclass=, and =Uize.Class.stateProperties= methods. All of these methods act on the class context. So, for example, calling =Uize.Class.subclass= is different to calling =Uize.Widget.subclass=. The =Uize.Class.subclass= method, which is inherited by all =Uize.Class= subclasses, uses the context of the class on which it is called. Calling the =Uize.Class.subclass= method returns a subclass of =Uize.Class=, while calling the =Uize.Widget.subclass= method returns a subclass of =Uize.Widget= - even though both of these methods reference the same function for their implementation (in other words, the statement =alert (Uize.Class.subclass == Uize.Widget.subclass)= would alert the text "true").

		Inheritability of Static Features is Noted in Module References
			All static features of modules of the UIZE JavaScript Framework are noted as being either inheritable or non-inheritable in the reference documentation for those features.

			The inheritability of the static features of a module is noted in the IMPLEMENTATION INFO notes of the reference documentation for the features in the module's reference. So, for example, if you went to the reference documentation for the =Uize.Class.set= static method of the =Uize.Class= base class, you would see it noted that the feature is inherited by subclasses. In contrast, if you went to the reference documentation for the =Uize.Fade.blendValues= static method of the =Uize.Fade= class, you would see it noted that the feature is *not* inherited by subclasses.

	Singletons
		The UIZE JavaScript Framework provides support for [[http://en.wikipedia.org/wiki/Singleton_pattern][singletons]] in the form of the =Uize.Class.singleton= static method that is implemented in the =Uize.Class= base class and is inherited by all =Uize.Class= subclasses.

		Every Class Supports Singletons
			Because singleton support is implemented in the =Uize.Class= base class, a singleton for any =Uize.Class= subclass can be created by calling the =singleton= static method on the class.

			EXAMPLE
			.......................................................
			var fileSystem = Uize.Services.FileSystem.singleton ();
			.......................................................

			In the above example, the =Uize.Services.FileSystem= class is a subclass of the =Uize.Service= class, which is itself a subclass of the =Uize.Class= base class. Therefore, a singleton can be created using the =Uize.Services.FileSystem.singleton= static method that is inherited from =Uize.Class=.

		A Single Singleton
			As expected with singletons, multiple separate calls to the =singleton= static method will return a reference to the same singleton.

			EXAMPLE
			........................................................................
			var
				fileSystemSingleton1 = Uize.Services.FileSystem.singleton (),
				fileSystemSingleton2 = Uize.Services.FileSystem.singleton ()
			;
			alert (fileSystemSingleton1 === fileSystemSingleton2);  // alerts "true"
			........................................................................

			In the above example, both the =fileSystemSingleton1= and =fileSystemSingleton2= variables are set to be a singleton of the =Uize.Services.FileSystem= class. Therefore, when their values are compared using a strict equality, they are found to be equal.

		Compelling Use Cases for Singletons
			A typical and compelling use case for the singleton feature is with service classes, where one typically wants to share a single instance of a service class amongst multiple disparate users of the service.

			In the case of service classes, one may instantiate and set up the singleton of a service in the environment (which will likely be a Web page for services that are to run in Web applications). Then, in other code that is to run in the environment and use the service, the singleton of the service can simply be obtained and used - the service doesn't need to be initialized by all the users because the same shared singleton of the service class is initialized and set up in the environment.

		Singleton Scope
			As a convenience, the =singleton= static method provides a way to optionally create singletons in a custom scope.

			A scope for a singleton of a class is specified using the optional =scopeSTR= parameter, as follows...

			EXAMPLE
			....................................................................................
			var fileSystemForBuildScripts = Uize.Services.FileSystem.singleton ('buildScripts');
			....................................................................................

			In the above example, a singleton of the =Uize.Services.FileSystem= class is being created in a scope we have decided to call "buildScripts". Now, any other build script code that wants to get a reference to this singleton can perform the same operation, specifying ='buildScripts'= as the value for the =scopeSTR= parameter. With this kind of arrangement, other code can now use the same =Uize.Services.FileSystem= service class in a different scope. In different scopes, the different singletons may be set up with different service adapters and initialized differently to perform different I/O.

			A Single Singleton Per Scope
				The exception to the rule of `a single singleton` is when using the `singleton scope` feature.

				EXAMPLE
				......................................................................
				var
					fileSystemInScopeA = Uize.Services.FileSystem.singleton ('scopeA'),
					fileSystemInScopeB = Uize.Services.FileSystem.singleton ('scopeB')
				;
				alert (fileSystemInScopeA === fileSystemInScopeB);  // alerts "false"
				......................................................................

				In the above example, two singletons of the =Uize.Services.FileSystem= class are being created: one in a scope we've called "scopeA" and the other in a scope we've called "scopeB". When the values of the =fileSystemInScopeA= and =fileSystemInScopeB= variables are compared using a strict equality, they are found to *not* be equal. However, if we called the =singleton= method multiple times for "scopeA", we would always get back the same singleton for this scope, and similarly with "scopeB".

			Designing Classes to Support Singleton Scope
				In order to be able to take advantage of the `singleton scope` feature, your classes need to be designed correctly.

				In order to correctly support singletons in different scopes, your class should not store state for a singleton as statics on the class, but should instead use instance properties. Provided your classes are designed correctly, you can have multiple singletons instantiated for different scopes that you define, so that different sets of distributed code can share their own singleton instances, and for each differently scoped singleton the singleton may be initialized or set up in a different way.

			Singleton Scope is Globalish
				A `singleton scope` is effectively global for a given class (so, not global in an absolute sense, but globalish).

				Therefore, if you have distributed code that is making use of the singleton feature and you are specifying a custom scope, you need to have a good degree of confidence that you won't have totally different code trying to use the same scope name for a singleton of a class where the initialization and usage of the singleton is different. This is the age old problem with things that are global in nature. The globalness of singletons is both the upside and the downside, so you should `use the singleton feature sparingly`.

		Initial State for Singletons
			A singleton can be created with an initial state by specifying the optional =propertiesOBJ= second parameter.

			EXAMPLE
			.................................................................................................
			var fileSystemForBuildScripts = Uize.Services.FileSystem.singleton ('',{defaultEncoding:'utf8'});
			.................................................................................................

			In the above example, a singleton is being created for the =Uize.Services.FileSystem= class. Because the first parameter of the =singleton= method is the singleton scope, if we want to use the default scope we need to specify an empty string. The second parameter is the state for the singleton, where the value is an object that will be passed to the constructor of the class if the singleton has not yet been created for the scope, or used in a call to the =set= method if the singleton already exists in the scope.

		Use the Singleton Feature Sparingly
			While there are a few `compelling use cases for singletons`, one should nevertheless use the singleton feature sparingly and with caution.

			The very advantage of singletons, which is that they can be shared by disparate pieces of code, can also become a disadvantage. Singletons can be regarded as being, in effect, globals in the scope of the class on which they are created, or the `singleton scope` in which they are created. This consequence brings with it the kinds of drawbacks that globals have more generally.

			Singletons aren't as egregious as global variables, and the `singleton scope` facility goes some way to alleviating the globalish nature of singletons. Nevertheless, before resorting to using singletons, consider first if there are other alternatives. In UIZE, you will find singletons mostly advocated for use with service classes.

	The "no new" Mechanism
		The JavaScript =new= operator is optional when creating instances of =Uize.Class= subclasses, and you can make the =new= operator optional for your own object constructors using the newly added =Uize.noNew= static method.

		Creating Instances of Uize Classes
			Because the =Uize.Class= base class utilizes `the "no new" mechanism`, one can create instances of any =Uize.Class= subclass either using the =new= operator or not.

			EXAMPLE
			................................................................................
			// this works
			var mySlider1 = new Uize.Widget.Bar.Slider ({minValue:0,maxValue:100,value:50});

			// Look ma, no "new"!!!
			var mySlider2 = Uize.Widget.Bar.Slider ({minValue:0,maxValue:100,value:50});
			................................................................................

		All Uize Classes Get the Benefit
			Because of the way in which `the "no new" mechanism` is implemented in the =Uize.Class= base class, any class that is derived from a =Uize.Class= base class using the =subclass= method gets the same benefit, including classes that you create for your own applications.

			This means, for example, that any widget class you create by subclassing the =Uize.Widget= class will get the same benefit. Consider the following example...

			EXAMPLE
			..................................................
			// we create a widget class
			var MyWidgetClass = Uize.Widget.subclass ();

			// this works
			var myWidgetClassInstance1 = new MyWidgetClass ();

			// Look ma, no "new"!!!
			var myWidgetClassInstance2 = MyWidgetClass ();
			..................................................

		Applies for Other Uize Objects
			`The "no new" mechanism`, that is implemented in the =Uize.noNew= static method, has been applied to various other =Uize= objects (such as the =Uize.Color= object) that are lightweight objects rather than full =Uize.Class= subclasses.

			So, for example, one can create instances of the =Uize.Color= object or the =Uize.Str.Builder= object without needing to use the =new= operator. Consider the following example...

			EXAMPLE
			.........................................
			// this works
			var fuchsia = new Uize.Color ('#ff0fff');

			// Look ma, no "new"!!!
			var olive = Uize.Color ('#808000');
			.........................................

		Using the Uize.noNew Method
			An object constructor that supports `the "no new" mechanism` can easily be created using the =Uize.noNew= static method.

			In cases where you're creating =Uize.Class= subclasses, you don't need to worry about the =Uize.noNew= method because `the "no new" mechanism` is built right into the =Uize.Class= base class, so `all Uize classes get the benefit`. However, in cases where you're defining your own lightweight objects, you can use the =Uize.noNew= method to create an object constructor where the =new= operator is optional. Consider the following example...

			EXAMPLE
			............................................................
			// define the Food object
			var Food = Uize.noNew (
				function (name,type) {
					this.name = name;
					this.type = type;
				}
			);

			// create an instance of Food using the new operator
			var apple = new Food ('apple','fruit');
			alert (apple.type);  // alerts the text "fruit"

			// create an instance of Food without using the new operator
			var rice = Food ('rice','grain');
			alert (rice.type);  // alerts the text "grain"
			............................................................

			What you'll notice from the above example is that the =Uize.noNew= method is quite simple - it takes a single parameter, which is the constructor function that initializes the new instance. This means that you can easily take an existing object constructor function and upgrade it to one that supports `the "no new" mechanism` by wrapping it inside a call to the =Uize.noNew= method, which then returns a wrapper constructor that becomes your new object constructor. Consider the following before-and-after example...

			BEFORE
			..............................................
			// must always use "new" with this constructor
			function Food (name,type) {
				this.name = name;
				this.type = type;
			}
			..............................................

			AFTER
			..........................................
			// "new" is optional with this constructor
			var Food = Uize.noNew (
				function (name,type) {
					this.name = name;
					this.type = type;
				}
			);
			..........................................

			Notice that you need to assign the result of the =Uize.noNew= method call, and so your original constructor function no longer should have the name.

	### OTHER NOTES
		Implementing Dual Context Methods
			.

		Private Static Methods
			- you really could just use global functions
			- is it a method or a function?
			- you can use =this= to reference other statics that might be overrided in a subclass

		Private Static Properties
			- when can you just use global variables?
			- in some cases, you might want private static properties that are inherited

		Private Instance Methods
			- two approaches
				- function whose first argument is context / this
				- function that is called as instance method on context, using _myPrivateMethod.call (this)

		Public Static Properties
			- accessing subclass' value from superclass

		Adding Handlers for Instance Events on Self
			instance event is fired in superclass' implementation

		Adding Handlers for State Property Changed Events on Self
			state property is declared by superclass

		Accessing State Properties From Subclass

		- don't expose purely static methods as instance methods just for convenience
			example
				MyClass.prototype.someStaticMethod = MyClass.someStaticMethod;

				now you can do...

				var instanceOfMyClass = new MyClass;
				instanceOfMyClass.someStaticMethod ();

				...instead, should use...

				var instanceOfMyClass = new MyClass;
				instanceOfMyClass.Class.someStaticMethod ();

//


koh5_pano



Your browser does not support the HTML5 canvas element.


Drag mouse to navigate.

Navigation





17.Aug.2010, Martin Wengenmayer