Getting Started

Aadit M Shah edited this page May 27, 2014 · 3 revisions

Although augment is a simple seven line function it is packed with features. It can be used for:

  1. Classical inheritance in JavaScript.
  2. Prototypal inheritance in JavaScript.
  3. Creating singleton instances.
  4. 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:

  1. 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 of Object and it would have made no difference.
  2. Inside a class this refers to the prototype of the class. Hence we can use augment it to create nested derived classes.
  3. If a class defines a constructor property then the constructor is returned. Otherwise the prototype is returned. Hence Shape is an object while Circle and Rectangle are functions.
  4. 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:

  1. Overriding base class methods.
  2. Calling overridden base class methods.
  3. Calling the base class constructor for initialization.
  4. Using augment to create modules and singleton instances.
  5. True prototypal inheritance using augment.