jClassy

Class system in JavaScript

Comparison with other libraries

Basic comparison of jClassy with class system core of several JavaScript libraries is provided.
Author
Ondřej Pavlata
Jablonec nad Nisou
Czech Republic
Document date
Initial releaseDecember 6, 2011
Last major release December 6, 2011
Last updateDecember 7, 2011

Table of contents

JavaScript native class system

In ideal circumstances, the JavaScript data model contains a structure that can be considered a native class system (also known as raw class system). In its basic reduct, which we denote NCS1, it is a structure of the form
(O, kind(), Object, Function, .prototype, .constructor, .__proto__) where The structure is subject to the following conditions:
(NCS1~1) .prototype and the restriction of .constructor to instance prototypes are inverses to each other, i.e. classes and instance prototypes are in one-to-one correspondence established by the .prototype and .constructor references.
(NCS1~2) The .__proto__ map forms a tree on objects, called the prototypal inheritance. The Object.prototype object is the inheritance root.
(NCS1~3) The .constructor map on instances and classes is inherited, i.e. for every instance or class x,
  • x.constructor == x.__proto__.constructor.
(NCS1~4) For every object x,
  • x is a class   iff   x.__proto__ == Function.prototype.
New class creation I
Plain classes can be created using the following newClass function.

Notes:

A sample native class-structure
The following diagram shows a sample restriction of an NCS1 structure. Single-directional (green) arrows indicate prototypal inheritance, bi-directional (blue) arrows indicate prototypeconstructor correspondence.
  Instance prototypes Classes
(alias constructors)
(alias functions)
 
•Object.prototype •Object







•Function.prototype •Function
•A.prototype •A
•B.prototype •B
•b Instances
The sample structure can be created by the following line of code. Subsequent code shows the established maps.
New class creation II
A more elaborate version of native class creation might look as follows. The membs argument is a definition object whose own properties (except the constructor property, if any) are mixed into the instance prototype of the created class. If the membs.constructor is supplied then it is taken for the new class. This native class creation method number II already supports native instance initializers and native parent method calls (aka supers).
Shortcomings
The native JavaScript class system is famous for its infamous features. In particular:
(Dreadful feature) Classes are synonymous to functions.
(Bad/unRuby feature)   A class does NOT inherit properties of its superclass.
(Bad feature) The class system has virtually no built-in support. In particular
  • The prototypeconstructor correspondence is not guaranteed.

 

Compared libraries

The following libraries () have been taken into consideration for their class system core:

Notes:

Comparison / correspondence tables

New class creation (plain subclassing)
The following table shows expressions used for new class creation. Expression result is a new class that has A as its direct superclass. If supported, the new class is named "B".

The last column shows that all libraries except jClassy provide a semi-support for native classes. This means that the corresponding class systems contain 2 kinds of classes:

Plain subclassing pattern Raw class A accepted?
JS.Class new JS.Class ("B", A)
YES
qooxdoo qx.Class.define ("B", { extend : A })
Dojo dojo.declare ("B", A)
MooTools new Class ({ Extends : A })
Ext JS 4 Ext.define ("B", { extend : A })
CoffeeScript class B extends A
jClassy klass.newClass ("B", A)
NO
Superclass / class maps
Inheritance tree/forest Class-map tree/forest
superclass reference root class reference root depth
JS.Class superclass none /
Object
klass JS.Class 2
qooxdoo superclass constructor
Dojo superclass.constructor constructor Function
MooTools parent $constructor Type 3
constructor Function 2
Ext JS 4 superclass.self self
superclass.constructor constructor Function
CoffeeScript __super__.constructor constructor Function
jClassy $parent c_.Object $class 2

Notes:

Member definition
In the following table, membs refers to the definition object.
Class creation Class modification
instance members class members instance members class members
JS.Class membs membs.extend include extend
qooxdoo membs.members membs.statics
Dojo membs extend
MooTools membs implement extend
Ext JS 4 membs membs.statics implement / override addStatics
CoffeeScript unsigiled members @-sigiled members single assignment
using '::' using '.'
jClassy def self_def
Mixin inclusion
Class creation Class modification
instance members class members instance members class members
JS.Class membs.include include extend
qooxdoo membs.include include / patch
Dojo <bases-but-last>
MooTools membs.Implements
Ext JS 4 membs.mixins
CoffeeScript
jClassy include, membs.$include
New instance creation / initialization
Creating a direct
instance of class A
Initialization method
JS.Class new A or new A(…) initialize
qooxdoo construct
Dojo constructor
MooTools initialize
Ext JS 4 constructor
CoffeeScript constructor
jClassy A.NEW (…) initialize
Class member inheritance (aka static inheritance)
Supported? Downward
synchronized?
Note
JS.Class
YES
Using downward propagation of own properties
qooxdoo
NO
Dojo
NO
NO support for class (static) members
MooTools
NO
Ext JS 4 NO publicly
YES internally
NO
Members to be inherited are refered to by inheritableStatics
CoffeeScript
YES
NO
jClassy
YES
Using prototypal inheritance
Parent method call (aka super)
Call pattern
(preserving arguments)
Applicable to
class methods?
Implementation
group
JS.Class this.callSuper()
YES
C2
qooxdoo this.base (arguments)
NO
B1
Dojo this.inherited (arguments)
???
MooTools this.parent (<arguments>)
C2
Ext JS 4 this.callParent (arguments)
B2
CoffeeScript super
A
jClassy this.pcall (arguments)
YES
B2

Notes:

Parent method call - Implementation
There are several basic ways how to implement parent method calls. The following table classifies libraries according to parent method call implementation.
Implementation
group
Subgroup Used in Strict mode
compliant?
A CoffeeScript
YES
B B1 qooxdoo
NO
B2 Ext JS 4, jClassy
C C1
YES
C2 JS.Class, MooTools
Class naming
Base (simple)
name
Pathname Nesting auto-creation
Supported? Nesting type
JS.Class displayName
NO
qooxdoo basename name
YES
plain objects
Dojo prototype.declaredClass
YES
plain objects
MooTools
NO
Ext JS 4 getName()
YES
plain objects
CoffeeScript name ()
NO
jClassy $name pathname()
YES
classes

Notes:

Name conflict resolution
Support
JS.Class
qooxdoo mixin compatibility check
Dojo
MooTools
Ext JS 4
CoffeeScript
jClassy extensive support

 

JS.Class

Object model
The JS.Class library establishes a modification of the Ruby object model []. The following is the main characteristics of the JS.Class object model in constrast to the Ruby model:
The sc-ec structure
The sc-ec structure (denoted S1 in []) is an inheritance substructure induced by the .sc and .ec maps between objects. As a substructure, the sc-ec structure uses a partition of the set of objects into classes, eigenclasses and terminals, as well as Class and Module as distinguished classes.

Notes:

A sample sc-ec structure
The following diagram shows a sample of an sc-ec structure, with sc-inheritance having 2 roots: Module and A. The .sc function (superclass reference) is indicated by green arrows (e.g. ), the .ec function (eigenclass reference) by blue arrows (). Objects A, B and b are assumed to be created by the code
var A = new JS.Class("A"), B = new JS.Class("B", A), b = new B;   (cf.[])
Primary objects
(alias classes
and terminals)
Secondary objects
(alias eigenclasses)
Eigenclass index → 0 1 2
Classives •Module  
•Module •   •  
•Module
•Class •   •  
•Module
•A •   •  
•Module
•B •   •  
•Module
Terminatives •b •   •  
The diagram is (partially) checked by the following code:

Notes:

The downside
The JS.Class object model has the following downside:
The model does NOT map well to JavaScript prototypal inheritance.
As a consequence, changes in object own properties (made by x.include(…) or by x.extend(…)) are propagated down the sc-inheritance forest.

The following code shows propagation of class members. The current implementation propagates even instance members. The following code shows that own instance members might get overwritten by the propagation. A property of b named 'zz' is set to '-zz-' using the extend method, then set to 8 by a plain assignment and then again reset to '-zz-' by updating instance members of b.klass.superclass.

 

References
1&1, qooxdoo, http://qooxdoo.org/
Jeremy Ashkenas, et al., CoffeeScript, http://coffeescript.org/
James Coglan, JS.Class, http://jsclass.jcoglan.com/
Dojo Foundation, Dojo Toolkit, http://dojotoolkit.org/
The MooTools Dev Team, MooTools, http://http://mootools.net/
Ondřej Pavlata, The Ruby Object Model: Data Structure in Detail, 2011, http://www.atalon.cz/rb-om/ruby-object-model
Ondřej Pavlata, jClassy: Class system in JavaScript, http://jclassy.org/
Sencha, Ext JS, http://www.sencha.com/products/extjs/
License
This document is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License.