This entry is part 3 of 4 in the series Dojo Foundation Packages

ComposeJS is a JavaScript package/module for object-oriented programming available in the Dojo Foundation package repository. JavaScript itself is already a highly object-oriented programming language, and the prototype-based inheritance system is very powerful. Rather than simply porting a “class” system from another language, the core philosophy of ComposeJS is to leverage JavaScript paradigms and enhance it with clean, terse syntax and modern composition and resolution concepts for simple, high-performance, and robust object constructors. ComposeJS uses concepts from class inheritance, multiple inheritance, mixins, traits, and aspect-oriented programming to compose functionality in the most efficient manner possible.

ComposeJS is designed to work across multiple JavaScript platforms, client and server, including Node.js and browsers, and can be loaded directly as a script or as a module (with Dojo, RequireJS, etc.). ComposeJS has clean, simple syntax in all of these environments. Generating constructors (or classes) is easy:

MyClass = Compose(BaseClass, {
  someMethod: function(){
  }
});

This is just a quick example of using ComposeJS. The API is highly flexible and permutative, allowing for multiple mixins, doing constructor delegation, handling conflict resolution, and more. The ComposeJS documentation provides ample examples and explanation. It is easy to compose structures from multiple entities, for example:

MySubClass = MyClass.extend(SomeMixin, SomeOtherMixin, {...});

However, I want to focus on the design concepts that drove the development of ComposeJS.

Simple Design Aligned with Native JavaScript

ComposeJS is designed to have an extremely simple, consistent API. The ComposeJS function can take any number of arguments, and each are treated the same. Each argument can be an object or a function. Each object’s properties and methods are available on instances of the ComposeJS generated class, and each function acts as a constructor, called on a instantiation (with its prototype mixed in). These means that the API is very easy to remember. ComposeJS can also work with constructors created from any source. You can use ComposeJS to compose classes from native classes (like Error), ComposeJS classes, classes created from Dojo, MooTools, etc., or constructors created with plain JavaScript. Since ComposeJS is based on core JavaScript principles, ComposeJS is extremely flexible.

ComposeJS also includes helper functions and extensions to fulfill a wide variety of programming needs. Compose.create can be used to instantly create an object, providing quick object delegation. Compose.apply can be applied to an existing object, allowing you to copy and mix in properties from one object to another. ComposeJS also includes decorator construction that allows you to create your own extensions for ComposeJS for more sophisticated object composition techniques.

Design Influences

Let’s look at some of the primary computer science concepts that have been developed over the years to deal with object composition:

  • Inheritance is the fundamental concept of inheriting functionality from other classes. Inheritance systems provide a means for overriding existing functionality. ComposeJS utilizes basic JavaScript (prototype-based) inheritance, making it easy to extend and override existing components.
  • Multiple inheritance is an extension of inheritance to compose functionality from multiple classes. The original design has largely been superseded by mixins and traits due to the fragility of only being able to compose with hard references to super classes.
  • Mixins are an improvement over multiple inheritance, allowing for more flexible composition of components, without relying on shared inheritance chains. ComposeJS utilizes the concept of mixins to combine functionality from different components.
  • Traits address the issues of composition of mixins when different parts of mixins need to be individually selected, providing a much more robust solution in the face of conflicting methods.
  • Aspects provide fine-grained composition of functionality for individual methods.

ComposeJS uses mixin-style ordered prioritization for default method resolution, but provides the conflict resolution capabilities of traits with method aliasing and exclusion control via the from() decorator. This allows you to enjoy the convenience of the mixins, plus the precise composition control of traits. Basically, you can assign a set of mixins and their order defines the priority of method override. When this is not fine-grained enough, you can explicitly rename methods and choose which method overrides others. When methods are in ambiguous placements in the hierarchy, they will resolve to a conflicted state to indicate that explicit selection is needed.

ComposeJS also strikes a pragmatic balance between the magically implicit C3 method resolution order (that few mortals can remember), and excessively explicit conflict resolution mandates of traits (where order is normally ignored). ComposeJS follows the simple rule that when explicit order has been supplied without conflicting order elsewhere, method resolution is determined, otherwise a conflict must be resolved.

ComposeJS also uses also provides aspect-oriented decorators to combine functionality of individual methods. This allows for super-call type functionality, but with the much more JavaScript oriented style of aspects, and the ease of using before, after, and around advice. This not only aligns more closely with idiomatic JavaScript, it is about twice as fast as traditional super-call approaches in JavaScript that search through the prototype chain for overridden methods. Aspect oriented decoration is also EcmaScript “strict mode” compatible (in fact ComposeJS opts for strict mode when available), whereas class constructors like dojo.declare are currently not compatible with strict mode.

Functional, Secure

ComposeJS is designed to follow principles of least authority. Creating new constructors or instances never modifies an existing object or the global scope (unless explicitly applied to an existing object using the “apply” API). ComposeJS creates new constructors and instances based on existing objects, preserving fundamental concepts of functional programming and avoiding sloppy side-effect based imperative programming styles. This also makes ComposeJS suitable for use in object capability security systems.

Installation

ComposeJS currently is a single file package. You can download the file from the github repository. ComposeJS is also available in the Dojo Foundation package repository, so you can also install it with CPM:

cpm install compose

Or you can install it for NodeJS:

npm install compose

Dojo and ComposeJS

ComposeJS is not Dojo specific, but can be used with Dojo classes. Because ComposeJS follows standard JavaScript prototype construction, ComposeJS can extend and mixin classes created with dojo.declare. Remember that dojo.declare‘s inherited() method won’t work from ComposeJS class methods, ComposeJS’ aspects should be used instead. ComposeJS is also being considered as a replacement for dojo.declare in Dojo 2.0.

Compose!

ComposeJS provides clean, simple, compact syntax for creating class-like constructors in JavaScript and is easy to start using. It builds on the best principles of composition and inheritance demonstrated in other languages, while maintaining a completely JavaScript oriented approach. ComposeJS has solid documentation, look through the explanations and examples and give it try!