Mozart
A full-featured, classical inheritance library for Node.js and the browser.
Install / Use
/learn @philipwalton/MozartREADME
Mozart
- Introduction
- Installation
- Getting Started
- API Documentation
- Browser and Environment Support
- Building and Testing
- Feedback and Contributing
Introduction
Mozart is a full-featured, classical inheritance library for Node.js and the browser. With Mozart you get:
- Simple subclassing.
- Private and protected methods and properties.
- Intuitive super method calling.
- Dynamic getter and setter generation.
Unlike most JS inheritance libraries, Mozart does more than just hide away the prototype boilerplate that nobody likes to remember. It also offers real data encapsulation, similar to what you'd find to most classical languages. Mozart uses the Private Parts module so you no longer have to prefix your properties with an underscore and hope that nobody touches them. Your public interface can be exactly what you want it to be.
Installation
Mozart is built for both Node and the browser. The browser version comes with a UMD wrapper, so it can be used as either an AMD module or as the global variable mozart.
To install from NPM:
npm install --save mozart
To install from Bower:
bower install --save mozart
Or you can download the latest version manually from Github.
Getting Started
Mozart provides a single factory method that can be used to create new constructors. When given no arguments, an anonymous constructor is returned. If passed a name, a constructor is created with that name (named constructors can be useful for debugging)*.
var ctor = require('mozart');
// Create an anonymous constructor.
var Foo = ctor();
// Create a named constructor.
var Bar = ctor('Bar');
If you're failing to see why the above code is useful, don't worry. The real value provided by Mozart comes from passing a class definition to the constructor factory (which I'll explain later). That being said, there are a few differences between Mozart constructors and regular JavaScript constructors worth pointing out.
The primary difference is that Mozart constructors are created for you, meaning you don't have the option to add any logic to them. This is intentional as much of the headache around traditional JS classical inheritance patterns comes from the fact that constructors are different from prototype methods and can't be invoked in all the same ways.
To solve this problem, the one (and only) thing Mozart constructors do is look for an init method on the prototype and (if found) call it (with the same arguments passed to the constructor). Moving the constructor logic to a prototype method simplifies everything. Inheritance is easier, and super methods can all be invoked in the same way.
In addition to this, Mozart constructors are packaged with five convenience methods: subclass, final, addGetters, addSetters, and addAccessors. More details about these methods can be found in the API documentation.
Class Hierarchies
The real power of the constructor factory method comes when you pass it a class definition. With a class definition you can write classes with public, private, and protected methods and properties.
The class definition is a function that is invoked with five arguments: the public prototype, the protected key function, the protected prototype, the private key function, and the private prototype. A detailed description of each can be found in the API documentation.
Note: if you don't know what a "key function" is, check out the Private Parts module to learn more.
Here's an example of Mozart in action:
var ctor = require('mozart');
var Citizen = ctor(function(prototype, _, _protected) {
// == PUBLIC ==
prototype.init = function(name, age) {
_(this).name = name;
_(this).age = age;
};
prototype.vote = function(politician) {
if (_(this).allowedToVote()) {
console.log(_(this).name + ' voted for ' + politician);
} else {
throw new Error(_(this).name + ' is not allowed to vote.');
}
};
// == PROTECTED ==
_protected.allowedToVote = function() {
return this.age > 18;
};
});
The above citizen class defines both public and protected methods and uses the passed key function to store data on the instance.
To subclass citizen, simply call its subclass method. As you'll see, two of the methods in this subclass (init and allowedToVote) are overridden and call super, and the vote method is simply inherited as you'd expect from a subclass.
var Criminal = Citizen.subclass(function(prototype, _, _protected) {
prototype.init = function(name, age, crime) {
_(this).crime = crime;
prototype.super.init.call(this, name, age);
};
_protected.allowedToVote = function() {
return _(this).crime != 'felony'
&& _protected.super.allowedToVote.call(this);
};
});
var joe = new Criminal('Joe', 27, 'felony');
joe.vote('Obama') // Throws: Joe is not allowed to vote.
In case it's not clear what's going on here, the class definition is providing you with two prototypes to define methods on. The public (regular) prototype, and the protected prototype (the _protected variable). Protected methods and properties are accessed using the protected key (the _ variable), and regular methods are accessed using this as usual.
When calling subclass on a constructor, a new class is formed that extends both the public and protected prototypes and makes them available to the subclass definition. It also stores a property called super that points to the parent class' respective prototypes for easy super method invocation. The protected key is also passed to the subclass allowing all instances of this class hierarchy to access it.
Getters and Setters
In most object oriented languages with classes, all instance variables are private (or protected) by default and the only way to access them is to create getters and setters.
With Mozart you can take the same approach, and you're provided a way to dynamically generate those methods to avoid extraneous typing.
Here's how you'd write getters and setters manually:
var Citizen = ctor(function(prototype, _) {
prototype.getName = function() {
return _(this).name;
};
prototype.setName = function(value) {
_(this).name = value;
};
prototype.getAge = function() {
return _(this).age;
};
prototype.setAge = function(value) {
_(this).age = value;
};
};
That's a lot of repetition. Here's how you'd do it dynamically with Mozart:
var Citizen = ctor(function() {
this.addGetters('name', 'age');
this.addSetters('name', 'age');
};
The above example calls the addGetters and addSetters methods on this, which in the context of the class definition is the constructor itself. It could alternatively have been written outside of the class definition:
var Citizen = ctor();
Citizen.addGetters('name', 'age');
Citizen.addSetters('name', 'age');
Lastly, if you want to add a getter and setter for the same property you could simply use addAccessors, which does both at the same time.
var Citizen = ctor();
Citizen.addAccessors('name', 'age');
API Documentation
The Constructor Factory
var ctor = require('mozart');
The Mozart module consists of a single factory method that can be used to create new constructors from a given class definition. All future examples assume the constructor factory is stored on the variable ctor as in the above example.
ctor([name], [definition])
Create a new constructor with an optional name and optional class definition.
name: {string} (optional) The name of the constructor.
definitionn: {Function} (optional) The class definition — a function that is invoked with the public, protected, and private keys and method objects.
The Class Definition
The class definition is the function passed to the constructor factory. This function defines the public, private, and protected methods.
The class definition function is invoked with the created constructor as its this context, and it's passed the following five arguments: prototype, protectedKey, protectedPrototype, privateKey, and privatePrototype.
By convention, those arguments are usually written as follows:
var MyConstructor = ctor(function(prototype, _, _protected, __, __private) {
// ...
})
publicPrototype
prototype {Object} The prototype of the returned constructor. In the above example, prototype would equal MyConstructor.prototype.
protectedKey
_ {Function} The protected key. This is used to get and set protected instance members. Protected instances can be accessed by the current class and its subclasses. (See Private Parts for more information on key functions.)
protectedPrototype
_protected {Object} The protected prototype. Use this object to store protected methods that are shared by all protected instances. Protected methods can be accessed by the current class and are inherited by its subclasses.
privateKey
__ {Function} The private key. This is used to get and set private instance properties. Private instances can only be accessed by the current class. (See Private Parts for more information on key functions.)
privatePrototype
__private {Obj

