- ×
jTypes is the most comprehensive and robust JavaScript library for overcoming differential inheritance with prototype-based objects. Its lightweight yet powerful design provides web programmers on any platform or browser the ability to emulate classical inheritance where objects are defined by classes.
Filed under application tools › utilitiesShow AlljTypes: Scalable class-based JavaScript for web apps and libraries
jTypes provides developers with robust type management in JavaScript to improve the maintainability and scalability of web-based applications. By utilizing familiar and proven design patterns from popular languages such as C++, C#, and Java, jTypes can simplify the development of web apps, libraries, and tools. Since it is not a new language, jTypes doesn't require any transcompilation to messy and unmaintainable JavaScript like other web programming languages. This makes it extremely simple and straightforward, especially for developers that are experienced with classical inheritance. Using existing and upcoming language components that are implemented across all browsers and platforms, jTypes offers an efficient and effective framework for class-based object-oriented development that can quickly and easily adapt to the "quirks" of a constantly evolving web.
Coming Soon: Precompiling Class Definitions
Contents
- Requirements
- Setup
- Classes
- Constraints
- Namespaces
- Class Modifiers
- Class Member Modifiers
- Global Settings
- Performance
- Futures
- Contribute
Requirements
jTypes requires ECMAScript 5, which is supported by any modern platform or browser. This includes the following desktop and mobile browser versions:
- Internet Explorer 9
- Firefox 4
- Chrome 13
- Safari 5.1
- Opera 11.6
- IE Mobile 9
- Android 3
- iOS Safari 5
- Opera Mobile 11.5
- Blackberry 7
IE Mobile 9 was released with the Windows Phone 7.5 update, also known as Mango; iOS 5 was released for the iPhone 3GS, iPhone 4, iPhone 4S, iPod Touch (3rd/4th gen), iPad, and iPad 2.
Setup
Include the
core.js
orcore.min.js
file in your application:<script type="text/javascript" src="jtypes-2.2.3.min.js"></script>
Install the jTypes module in Node.js using npm:
npm install jtypes
Enabling ECMAScript 6 features with the --harmony flag is recommended for jTypes 2.2 when using preview release 0.11.0 or higher.
IntelliSense
The
core.intellisense.js
file can be included in Visual Studio 2012 to add support for IntelliSense with jTypes:This file is also available in the .zip downloads on our website.
Classes
Classes help organize applications and libraries by promoting the reuse of code and facilitating the ease of maintainence. They are created by providing the jTypes compiler with a definitions object in the following format:
Class jTypes([String modifiers,] [Class base,] [Function constructor,] Object definitions)
This definitions object is a template for creating instance objects. It provides initial primitive values for fields, and function references for methods and properties. These default field values must be primitives such as booleans, numbers, strings, or symbols; otherwise the compiler will use a default value of
null
. The following example compiles a classColor
and defines the initial primitive values of three public fields:var Color = jTypes( { 'public red': 0, 'public green': 0, 'public blue': 0 }); var color = new Color(); console.assert(color.red === 0, 'Color.red'); console.assert(color.green === 0, 'Color.green'); console.assert(color.blue === 0, 'Color.blue'); color.red = []; color.green = new Date(); color.blue = {}; console.assert(jTypes.isArray(color.red), 'Color.red'); console.assert(jTypes.isDate(color.green), 'Color.green'); console.assert(jTypes.isSimpleObject(color.blue), 'Color.blue');
If an instance of the
Color
class is instantiated, the fields will have their default primitive values. This is demonstrated by theassert()
calls in the previous example. These fields can then be assigned any type of reference upon instantiation such as arrays, dates, functions, or objects.Constructors
jTypes('Color', function(red, green, blue) { this.red = red; this.green = green; this.blue = blue; }, { // ... }); var gray = new jTypes.Color(128, 128, 128);
Fields
jTypes('Color', function(red, green, blue) { // ... }, { 'public readonly red': 0, 'public readonly green': 0, 'public readonly blue': 0 }); var gray = new jTypes.Color(128, 128, 128); //gray.red = null; (throws)
Properties
jTypes('Color', function(red, green, blue) { this._red = red; this._green = green; this._blue = blue; }, { 'private _red': 0, 'private _green': 0, 'private _blue': 0, 'public red': { 'get': function(){ return this._red }, 'protected set': function(v){ this._red = v } }, 'public green': { 'get': function(){ return this._green }, 'protected set': function(v){ this._green = v } }, 'public blue': { 'get': function(){ return this._blue }, 'protected set': function(v){ this._blue = v } } }); var gray = new jTypes.Color(128, 128, 128); //gray.red = null; (throws)
Automatically Implemented Properties
jTypes('Color', function(red, green, blue) { // ... }, { 'public red': ['get', 'protected set'], 'public green': ['get', 'protected set'], 'public blue': ['get', 'protected set'] }); var gray = new jTypes.Color(128, 128, 128); //gray.red = null; (throws)
Inheritance
var AlphaColor = jTypes('sealed', Color, { 'public opacity': 0 }); var color = new AlphaColor(); // ...
In the next example, the
Color
class is compiled without referencing the return value of the compiler:jTypes('Color', { 'public red': 0, 'public green': 0, 'public blue': 0 }); var color = new jTypes.Color(); // ...
The
modifiers
argument of the jTypes compiler accepts a space-separated string of keywords. However, if the final keyword in the modifiers string starts with a capital letter, it will be treated as a class name and be globally defined in the jTypes namespace.Constraints
Type constraints restrict values to simplify the implementation and maintainence of classes. If a value is not of the respective type of the constraint, it is treated as a null reference instead:
array
Class
date
element
(2.2.1)error
function
jquery
(2.2.1)object
primitive
regexp
type
window
The type constraint
object
strictly checks for invalid values using a$$.type(...)
that is equal to'object'
, whileprimitive
checks for invalid values using the$$.isPrimitive(...)
method, andtype
checks for invalid values using the$$.isClass(...)
method. The following example compiles a classQueue
with the type constraintarray
on a protected field:jTypes('Queue', function() { // ... }, { 'protected array _queue': null, // ... 'public dequeue': function() { if (this._queue) return this._queue.shift(); } });
If the protected field is checked for a null reference in the
dequeue()
method, it is guaranteed to have a$$.type(...)
equal to'array'
and can safely call theshift()
method. If a class has its name defined in the modifiers string as in the previous example, it can also be used as a constraint:jTypes('Element', function() { // ... }, { 'public Queue animations': null, // ... }); var element = new jTypes.Element(); // ... while (element.animations) { var animation = element.animations.dequeue(); if (!animation) break; // ... }
Because the
animations
field is restricted using the type constraint, it is guaranteed to be of the typeQueue
and can safely call thedequeue()
method.Primitive Constraints
Primitive constraints use the primitive values
false
,0
,NaN
,""
, andSymbol()
for default or invalid values instead of null references. Consequently, these values can be directly accessed without any reference checking because they always provide a primitive value that is neitherundefined
nornull
:boolean
(bool
)integer
(int
)number
(float
)string
symbol
These constraints prevent values from being cross referenced because they implicitly convert wrapper objects such as
new Number(...)
to its primitive value. The following example compiles a structColor
using the type constraintint
on the public fields:jTypes('struct Color', function(red, green, blue) { // ... }, { 'public int red': 0, 'public int green': 0, 'public int blue': 0, // ... }); var green = jTypes.Color(); green.red = '255'; green.green = 128.3; green.blue = null; console.assert(green.red === 0, 'Color.red'); console.assert(green.green === 128, 'Color.green'); console.assert(green.blue === 0, 'Color.blue');
Since the values
'255'
andnull
do not have atypeof
that is equal to'number'
, the fieldsgreen.red
andgreen.blue
are assigned the default value of0
. However,green.green
is assigned a truncated value because128.3
is a primitive number.Struct Constraints
Struct constraints use default instances for default or invalid values instead of null references. These values can also be directly accessed without any reference checking because they always provide a default instance:
Struct
The following example compiles the class
Element
using the type constraintColor
on the public fields:jTypes('Element', function() { // ... }, { 'public Color background': null, 'public Color foreground': null, // ... }); var element = new jTypes.Element(); // ... var background = '#' + element.background.red.toString(16) + element.background.green.toString(16) + element.background.blue.toString(16), foreground = '#' + element.foreground.red.toString(16) + element.foreground.green.toString(16) + element.foreground.blue.toString(16);
The values of
element.background
andelement.foreground
in the previous example can be directly accessed without any reference checking because they always provide aColor
struct.Because default and invalid values of fields and automatically implemented properties are still internally stored as null references, default struct instances are not instantiated until the value is accessed.
Operators
Nullable Operator
The
?
nullable operator defaults primitive constraints and structs to null references for invalid values. It can be postfixed to the following constraints:boolean?
(bool?
)integer?
(int?
)number?
(float?
)string?
Struct?
symbol?
This allows primitive constraints to comply with primitive data types that may not contain a value, and structs to replicate the behavior of models. The following example compiles an abstract class
Shape
with the?
operator postfixed to the type constraintColor
:jTypes('abstract Shape', { 'protected Color? _fill': null, 'protected Color? _stroke': null, // ... 'public abstract string toString': null });
Since the protected fields default to null values, any derived implementation of the
Shape
class must check their values for null references. The next example compiles a classPolygon
with a non-primitive type constraintarray
on another protected field:jTypes('Polygon : Shape', function() { // ... }, { 'protected array _points': null, // ... 'public override string toString': function() { var attributes = ""; if (this._points) attributes += 'points="' + this._points.join(' ') + '" '; // ... if (this._stroke) attributes += 'stroke="' + this._stroke + '" '; return '<polygon ' + attributes + '/>'; } });
Because the inherited field
this._stroke
from the previous example is nullable, it must first be checked for a null reference before being concatenated in thetoString()
method, which is also the case withthis._points
and calling thejoin()
method.Not-Nullable Operator
The
!
not-nullable operator prevents built-in constraints with default instances from using null references. Because primitive constraints only default to null values when the nullable operator is present, the not-nullable operator can be postfixed to the following non-primitive constraints:array!
date!
error!
function!
jquery!
(2.2.1)Model!
object!
regexp!
This operator can be postfixed to models due to the fact that models do not call the constructor unless the
new
operator is present. The example below compiles a classQueue
with the!
operator postfixed to the type constraintarray
:jTypes('Queue', function() { // ... }, { 'protected array! _queue': null, // ... 'public dequeue': function() { return this._queue.shift(); } });
Since the operator uses default instances for invalid values instead of null references, the
dequeue()
method in the previous example can safely call theshift()
method without checking the protected field for a null reference.Because default and invalid values of fields and automatically implemented properties are still internally stored as null references, default model instances are not instantiated until the value is accessed.
Coerce Operator
The
~
coerce operator performs implicit conversions for built-in types. It can be prefixed to the following constraints:~array
~boolean
(~bool
)~date
~integer
(~int
)~number
(~float
)~regexp
~string
This operator converts values using global casting methods such as
$$.asArray(...)
or$$.asString(...)
. It does not alter the default value of fields and automatically implemented properties for non-primitive constraints. The following example compiles a structColor
with the~
operator prefixed to theint
type constraints:jTypes('struct Color', function(red, green, blue) { // ... }, { 'public ~int red': 0, 'public ~int green': 0, 'public ~int blue': 0, // ... }); var orange = jTypes.Color(); orange.red = '255'; orange.green = '0xA5'; orange.blue = null; console.assert(orange.red === 255, 'Color.red'); console.assert(orange.green === 165, 'Color.green'); console.assert(orange.blue === 0, 'Color.blue');
Since none of the values being assigned to the fields in the previous example are primitive numbers, the
$$.asInt(...)
casting method will be used to coerce the values. To alter the default value of fields and automatically implemented properties for non-primitive constraints, the~
and!
operators can be prefixed and postfixed:~array!
~date!
~regexp!
Suppress Operator
at-symbol =>
@date
suppresses errors when
jTypes.strict = true
Strict Constraints
require
jTypes.strict = true
, throw errors when a value is set that does not match the type of the constraint or !==null
(which cannot be applied to constraints with the coerce modifier)Namespaces
Namespaces help organize applications and libraries by controlling the scope of classes. They are created by providing the jTypes compiler with a callback function in the following format:
Object jTypes([String modifiers,] [Array dependencies,] Function callback(jTypes))
This callback is invoked in the context of a namespace object. Using the provided argument, calls to the compiler will also be within the scope of the namespace.
If a modifiers string is not provided, the callback is invoked in the context of the global namespace.
In the following example, a struct
Color
is compiled in the scope of theSystem.Drawing
namespace:jTypes('namespace System.Drawing', function($$) { $$('struct Color', function(red, green, blue) { // ... }, { // ... }); var gray = new this.Color(128, 128, 128); });
The namespace modifier in the modifiers string is optional and can be provided for readability.
Since this callback is invoked in the context of the namespace, the struct can be instantiated using
this.Color
in the scope of the callback function. Other scopes can instantiate this struct using the fully qualified reference from the global namespace:var white = new jTypes.System.Drawing.Color(255, 255, 255);
These scopes also allow base classes and type constraints to be resolved from either the current or parent namespaces without requiring a fully qualified name. In the next example, an abstract class
Shape
is compiled in the scope of theSystem.Drawing.Drawing2D
namespace:jTypes('namespace System.Drawing.Drawing2D', function($$) { $$('abstract Shape', { 'protected Color _fill': null, 'protected Color _stroke': null, // ... }); });
The type constraint
Color
on the fields of theShape
class can be resolved without using the fully qualified name because the struct is defined in a parent namespace. If a classRectangle
is compiled in the same namespace as outlined in the example below, it can also reference theShape
class without using the fully qualified name:jTypes('namespace System.Drawing.Drawing2D', [ // ... ], function($$) { $$('Rectangle : Shape', function() { // ... }, { // ... }); });
While the
Rectangle
class is compiled in a separate callback function with its own unique scope and dependencies, theShape
class can still be referenced because it is already defined in theSystem.Drawing.Drawing2D
namespace.Dependencies
If a base class or type constraint cannot be resolved from either the current or parent namespaces, a dependencies array can prevent the need to specify a namespace or fully qualified name. The following example compiles an abstract class
Control
in theSystem.Forms
namespace using an array of dependency strings:jTypes('namespace System.Forms', [ 'using System.Drawing', 'using System.Drawing.Drawing2D', // ... ], function($$) { $$('abstract Control', { // ... }); });
This array of dependency strings can contain two types of declarations; alias definitions and namespace includes. Alias definitions contain the
=
assignment operator, while namespace includes do not.Includes
Namespace includes allow identifiers in a namespace to be resolved without having to specify the namespace. The example below includes the
System.Drawing
namespace in the scope of the callback function:jTypes('namespace System.Forms', [ 'using System.Drawing', // ... ], function($$) { $$('Textbox : Control', function() { // ... }, { 'public virtual Color background': ['get', 'set'], 'public virtual Color border': ['get', 'set'], // ... }); });
Since the
System.Drawing
namespace is included in the scope, the type constraintColor
on the automatically implemented properties can be resolved without usingDrawing.Color
orSystem.Drawing.Color
.If a base class or type constraint is ambiguous between namespace includes, then it must be uniquely qualified.
Aliases
Alias definitions make it easier to qualify an identifier for a class or namespace. The next example creates the alias
Color
for the fully qualified nameSystem.Drawing.Color
:jTypes('namespace System.Forms', [ 'using Color = System.Drawing.Color', // ... ], function($$) { $$('Textbox : Control', function() { // ... }, { 'public virtual Color background': ['get', 'set'], 'public virtual Color border': ['get', 'set'], // ... }); });
Because this alias is defined in the scope of the callback function, the type constraint
Color
on the automatically implemented properties can be resolved. The fully qualified name on the right side of the alias definition can also beDrawing.Color
due to the fact thatSystem.Forms
is a child namespace ofSystem
.Aliases cannot hide a class already defined in the current namespace.
When there are conflicting names, aliases can be referenced directly using the
::
operator. The following example uses the namespace alias qualifier to directly reference an alias in the type constraints on the automatically implemented properties:jTypes('namespace System.Forms', [ 'using Drawing = global::System.Drawing', // ... ], function($$) { $$('Textbox : global::System.Forms.Control', function() { // ... }, { 'public virtual Drawing::Color background': ['get', 'set'], 'public virtual Drawing::Color border': ['get', 'set'], // ... }); });
The right side of an alias definition must be a namespace to use it with the
::
operator. Theglobal::
namespace alias qualifier is reserved for the global namespace. This allows base classes and type constraints to be referenced using globally qualified names.Class Modifiers
abstract
abstract classes: cannot be instantiated and can have abstract methods and properties
expando
expando classes: inject the
__self
object into the root of prototype chain of the instance matrix (and it is only available in legacy mode)internal
internal classes: hide their type from the type() method on all instances and the __type accessor on the public instance (and non-internal classes cannot inherit from internal classes)
model
models: have optional constructors (new operator invokes constructor), default instances (without new operator)
optimized
optimized classes: dynamically create instance objects (and it is not available in legacy mode)
primitive
primitive classes: have primitive type constraints (for fields and automatically implemented properties), clone() and equals(obj) methods
sealed
sealed classes: cannot be inherited
struct
structs: have optional constructors (new operator invokes constructor), default instances (without new operator), no inheritance, clone() and equals(obj) methods
unlocked
unlocked classes: have chainable __base instances
Class Member Modifiers
abstract
abstract members: must be overridden in a derived class (and can only be used on methods or properties)
const
const members: are not
[Writable]
and can only be used with theprototype
orstatic
modifiershidden
hidden members: are not
[Enumerable]
(fields and properties are enumerable by default, methods are not)new
new members: hide an inherited member (when not overriding)
override
override members: override an inherited abstract or virtual member
private
private members: are only accessible in the methods and properties of the class they are defined in
protected
protected members: are only accessible in the methods and properties of the class they are defined in and the methods and properties of any derived classes
prototype
prototype members: are defined on the prototype of the class constructor (
Class.prototype
)public
public members: are accessible everywhere for the class they are defined in and any derived classes as well
readonly
readonly members: are only writable inside the constructor (and can only be used with fields and automatically implemented properties)
sealed
sealed members: cannot be overridden and must be used with the
override
modifierstatic
static members: are defined on the class constructor (
Class
)virtual
virtual members: can be overridden in a derived class (and can only be used on methods or properties)
visible
visible members: are
[Enumerable]
(methods are not enumerable by default, fields and properties are)Global Settings
jT_FunctionLock
default:
false
jT_Harmony
default:
true
jT_Legacy
default:
false
jT_PrototypeLock
default:
false
jT_Shorthand
default:
true
jT_Storage
default:
false
jT_Writable
default:
false
Performance
Futures
- Generics
- Interfaces
- Events (Prioritized Queues)
- DOM Event Binders
- Dynamic Namespaces
- Internal Methods and Accessors
- Custom Constraint Handlers
- Argument Type Constraints (Methods)
- Factories
- Indexers *
- Partial Classes
- Observable Classes *
- Reflection (Introspection)
* Requires ECMAScript 6 Proxies
Precompiling (fusion Integration)
jTypes will soon provide support for precompiling static class definitions using our fusion language framework currently under development. The lexer-parser utilities of fusion will be used to build an abstract syntax tree for each static class definition in a
.jt
file and transpile them into a.js
file. Any classes with inline strings, functions, and object literals will be transpiled into a jTypes class that requires no compiling at runtime. This will provide developers with the ability to utilize dynamic runtime class definitions for rapid prototyping and precompiled static class definitions for efficiency. It not only offers the best of both worlds, but allows your class definitions to be interchangeable between the two.https://github.com/gaulinsoft/fusion
The fusion language superset can also be combined with jTypes in
.fjt
files to allow for inline HTML and CSS in class definitions.Media