-
Notifications
You must be signed in to change notification settings - Fork 38
Getting Started
Although augment
is a simple seven line function it is packed with features. It can be used for:
- Classical inheritance in JavaScript.
- Prototypal inheritance in JavaScript.
- Creating singleton instances.
- Creating modules.
We'll start with the type signature of augment
:
augment :: Function | Object // A base class constructor or prototype
-> Function // The definition of the new class or prototype
-> ... // A bunch of other optional arguments
-> Function | Object // Return a new class or prototype
Now we'll use augment
to create a simple Shape
data type:
var extend = augment.extend;
var Shape = augment(Object, function () {
this.Circle = extend(this, {
constructor: function (x, y, r) {
this.x = x;
this.y = y;
this.r = r;
},
area: function () {
return Math.PI * this.r * this.r;
}
});
this.Rectangle = extend(this, {
constructor: function (x1, y1, x2, y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
},
area: function () {
return Math.abs((this.x2 - this.x1) * (this.y2 - this.y1));
}
});
});
As you can see Shape
inherits from Object.prototype
while Circle
and Rectangle
inherit from Shape
. Creating nested derived classes using augment
is simple. Now let's create some instances:
var circle = new Shape.Circle(0, 0, 10);
var rectangle = new Shape.Rectangle(0, 0, 8, 6);
alert(Shape.isPrototypeOf(circle)); // true
alert(circle instanceof Shape.Circle); // true
alert(circle.area()); // 314.1592653589793
alert(Shape.isPrototypeOf(rectangle)); // true
alert(rectangle instanceof Shape.Rectangle); // true
alert(rectangle.area()); // 48.0
From the above code we learn the following:
- It doesn't matter whether the base class is a constructor or the prototype of the constructor. The output will always be the same. For example we could have used
Object.prototype
in place ofObject
and it would have made no difference. - Inside a class
this
refers to the prototype of the class. Hence we can useaugment
it to create nested derived classes. - If a class defines a
constructor
property then the constructor is returned. Otherwise theprototype
is returned. HenceShape
is an object whileCircle
andRectangle
are functions. - The
constructor
property need not be a function. However it's best if you only use it as a function.
As you can see although augment
is so simple yet it is very powerful. It's prototypal nature disguised as classes allows you to easily create Algebraic Data Types from functional languages. For example the above Shape
data type would be written in Haskell as:
data Shape = Circle Double Double Double
| Rectangle Double Double Double Double
area :: Shape -> Double
area (Circle _ _ r) = pi * r * r
area (Rectangle x1 y1 x2 y2) = abs $ (x2 - x1) * (y2 - y1)
main = do
print . area $ Circle 0 0 10
print . area $ Rectangle 0 0 8 6
Using augment
promotes modularity. It encourages you to create separate files for different data types. Exporting them is very easy. For example here's how you would export the Shape
data type:
if (typeof define === "function" && define.amd) define(Shape);
else if (typeof module === "object") module.exports = Shape;
In the case of browsers Shape
is already a global (declared as a var
). Hence you don't need to export it. Thus augment
allows you to easily modularize your programs into various "class" files.
This is all you need to know to get started with augment
. Algebraic Data Types go a long way. In the coming articles you can learn more about the following:
- Overriding base class methods.
- Calling overridden base class methods.
- Calling the base class constructor for initialization.
- Using
augment
to create modules and singleton instances. - True prototypal inheritance using
augment
.