alamid-class
Easy prototype inheritance.
alamid-class is a lightweight library (~1.2 kb compressed and gzipped) that allows you to write classes in JavaScript intuitively. It embraces the dynamic and prototypal nature of JavaScript instead of pretending to be a compiled language like Java.
This library is not intended to obscure prototypal inheritance. There are some caveats you should know about if you're new to it.
Setup
Quick Start
Syntax
The syntax is easy to grasp and expressive. A simple class looks like this:
var Class = ; var Cat = name: "Jimmy" age: 3 { thisname = name || thisname; thisage = age || thisage; } { console; };
var cat = ;console; // trueconsole; // "Jimmy"console; // false because it is inherited by the prototype
Inheritance
Now you can extend that class with:
var Octocat = Cat;
The special function this._super()
inside a method provides access to the overridden method. In this case it's simply a shortcut for Cat.prototype.strollAround.call(this)
var octocat = ;console; // trueconsole; // "Octocat"console; // "sad"octocat; // "Seeking parents ... but in the meantime: // MEEEOOOWWW!!! Need food! Now!"
You can also inherit from existing prototypes just like that:
var MyEventEmitter = ;
Additionally all instances provide a read-only reference called Class
on the function that created the instance:
console; // Catconsole; // Octocat
Mixins
Mixins are always part of a flexible class system. In alamid-class a mixin can be any object which will be merged into the prototype.
var Orphan = { console; };
var Octocat = Cat; var octocat = ;octocat; // "No parents found. Octocat is feeling sad now..."
This way you can easy leverage multiple inheritance:
var Orphan = {};var Octocat = Cat; var octocat = ;octocat;octocat; // "No parents found. Octocat is feeling sad now..."
If two mixins define a property with the same name, the latter mixin will simply override the former. This especially applies to the constructor
, so be sure to call it manually.
A class itself can also augment existing objects:
var someObj = {};Octocat;Octocat; // Applying the constructor manually someObj; // "No parents found. Jimmy is feeling sad now..."
Dev-mode
For a nicer debugging experience and better stack traces you can give your classes names. Take a look at the difference:
But in order to set the function's name alamid-class needs to use eval(). Since eval() is slow and you usually don't need class names in production, this feature is only available when Class.dev = true
. In production mode, names are simply ignored.
You can set a name like this:
var Cat = "Cat" ...; var Octocat = Cat;
API
var Class = ;
new Class(name?, proto1, proto2, ...): Class
Creates a new function that will use the given prototypes.
-
name (optional):
Specifies the name of the returned function. Works only in dev-mode. Defaults to"AnonymousClass"
-
proto1, proto2, ...:
Multiple prototypes that will be merged into one prototype (while the latter prototype overrides the former). If the given prototype is typeof function, its prototype is used instead. So, passingfunc
orfunc.prototype
is the same.
class.extend(name?, proto1, proto2, ...): Class
Creates a new function that will inherit from class
and implement the given prototypes.
class.mixin(obj): Class
Copies all properties of class.prototype
to the given target. Returns class
.
- obj:
The target object that receives all properties.
Class.dev
Boolean variable that switches alamid-class to dev-mode. Defaults to false. Checkout the example.
Notes
Object and arrays as properties
Since object and arrays are copied by reference in JavaScript all instances will share the same object as property. Imagine this class:
var MyClass = myObj: {}; var a = ;var b = ;console; // true
This is a common misconception when using prototypal inheritance. So, if you want an object for each instance you should create it within the constructor like this:
var MyClass = myObj: null { thismyObj = {}; }; var a = ;var b = ;console; // false
How does this._super work?
While this is basically accomplished with John Resig's trick, it has been tweaked so the function's length
-attribute isn't modified.
Asynchronous calls of this._super
There is one problem with Resig's technique: If the call on this._super() is asynchronous, this._super may point to another function. So, instead of this:
{ var self = this; ; }
you should do:
{ var self = this super = this_super; ; }
Class
Read-only property Every instance provides a read-only reference called Class
to the function that created the instance. Some could argue that alamid-class should use the built-in constructor
-property for that. The problem is, that constructor
always points to the topmost function in the prototype-chain:
{} {}Bprototype = Object; console; // trueconsole; // false
That's the reason why alamid-class introduces a new read-only reference to the function that has been called by new
.
About alamid
alamid-class has been extracted as standalone library from the application framework alamid.
Contributing
Suggestions and bug-fixes are always appreciated. Don't hesitate to create an issue or pull-request. All contributed code should pass
- the tests in node.js by running
npm test
- the tests in all major browsers by running
npm run test-browser
and then visitinghttp://localhost:8080/bundle