augment.js

The world's smallest and fastest classical JavaScript inheritance pattern (Function.prototype.augment) is a seven line function which allows you to write CoffeeScript style classes with a flair of simplicity; and it still beats the bejesus out of other JavaScript inheritance libraries.

Inspired by giants like Jeremy Ashkenas and John Resig, augment is an augmentation of ideas. Classes created using augment have a CoffeeScript like structure, and a syntax like John Resig's; but they are more readable, intuitive and orders of magnitude faster. Plus they work on every JavaScript platform.

Table of Contents

  1. Installation and Usage
  2. Creating your First Class
  3. Creating your Second Class
  4. Creating your Third Class
  5. CoffeeScript Like Structure
  6. Syntax Like John Resig's

Change Log

  1. 1.0.0 - Extended Function.prototype with a method named augment which allows you to create CoffeeScript style classes easily in JavaScript using a syntax like John Resig's.
  2. 1.1.0 - Implemented three new functions on Function to ease functional programming - namely bindable, callable and applicable.

Extending Native Prototypes

The javascript/augment library extends native prototypes. Yes, extending native prototypes is considered bad practice but I'm still doing it because:

  1. JavaScript programmers are too scared of extending native prototypes. So I'm not afraid that some other library will break my code.
  2. I pick the names of the methods I'm adding very carefully. For example all other JavaScript inheritance libraries use extend to create a subclass. I use augment.
  3. I am reserving some names like augment for myself. Don't get mad - Jeremy Ashkenas reserved the underscore and John Resig reserved the dollar sign.
  4. JavaScript allows you to extend native prototypes. It's not against the spirit of the language or else it wouldn't be possible in the first place.
  5. Crockford has dedicated a section about extending native prototypes in his book JavaScript: The Good Parts, and he's not against using it.

Documentation

We wrap up the javascript/augment library in an immediately invoked function expression to create a namespace.

(function (functProto, arrayProto) {

Check whether Object.create exists.

    if (typeof Object.create !== "function") {

Crockford's fallback for the Object.create function, with little more descriptive names.

        Object.create = function (prototype) {

Set the prototype of constructor to prototype.

            constructor.prototype = prototype;

Return a new instance of constructor.

            return new constructor;

Declare constructor.

            function constructor() {}

This is an incomplete polyfill for older JavaScript engines. It doesn't support the second argument to Object.create.

        };

Dear Brendan Eich, I think we should implement three new native functions on Function.prototype - namely create, construct and instantiate. Because of the nature of these methods it's necessary to make them native. They'll be greatly beneficial to everyone.

    }

We extend the prototype of Function with augment so that any function can be augmented (extended). The method augment has a single parameter which is called classBodyFunction simply because it's a function which contains the body of the class.

    functProto.augment = function (classBodyFunction) {

Line 1: Save the prototype of the base constructor in a variable called uber. We can't use super because it's a reserved word and I don't like using underscores (_super abhors me).

        var uber = this.prototype;

Line 2: Create an object which inherits from the prototype of the base constructor. This object will be used as the prototype of the class, making its instances an instanceof the base constructor as well.

        var prototype = Object.create(uber);

Line 3: Call classBodyFunction with the base constructor and uber as arguments. The public properties of the class are collected on the newly created prototype object. The classBodyFunction should return the constructor of the class.

        var constructor = classBodyFunction.call(prototype, this, uber);

Line 4: If classBodyFunction doesn't return a constructor then provide a default constructor which does nothing.

        if (typeof constructor !== "function") constructor = function () {};

Line 5: Set the constructor property of the prototype object to point to the constructor.

        prototype.constructor = constructor;

Line 6: Make prototype the prototype of the constructor function.

        constructor.prototype = prototype;

Line 7: That's it. Simple no?

        return constructor;

If you think that this is an amazing function and that the code the CoffeeScript compiler generates is a mess then send an email to Jeremy Ashkenas asking him to fix it using this method instead. It's a win for everyone.

    };

Store bind in a local variable.

    var bind = functProto.bind;

The function bind.bind is a powerful feature which makes a function easily bindable. This allows you to make higher order functions like call and apply bindable so that you may easily bind them to other functions like Object.prototype.toString.

    var bindable = Function.bindable = bind.bind(bind);

The function callable is a bindable version of call. You may use it to easily bind call to other functions. It's equivalent to call.bind.

    var callable = Function.callable = bindable(functProto.call);

The function applicable is a bindable version of apply. You may use it to easily bind apply to other functions. It's equivalent to apply.bind.

    var applicable = Function.applicable = bindable(functProto.apply);

Pass Function.prototype to the javascript/augment library as functProto.

})(Function.prototype, Array.prototype);