Skip to content
This repository has been archived by the owner on Jul 9, 2022. It is now read-only.

Classical Inheritance

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

Since augment is primarily a classical inheritance pattern let's create some classes. We'll start by implementing the EventStream class which is personally my favorite class:

var defclass = augment.defclass;

var EventStream = defclass({
    constructor: function () {
        this.argc = arguments.length;
        this.argv = arguments;
        this.listeners = [];
    },
    emit: function (event) {
        var listeners = this.listeners, length = listeners.length, index = 0;
        while (index < length) listeners[index++](event);
        this.argc = 0;
    },
    addListener: function (f) {
        var argc = this.argc, argv = this.argv, index = 0;
        while (index < argc) f(argv[index++]);
        this.listeners.push(f);
    },
    map: function (f) {
        var events = new Events;

        this.addListener(function (x) {
            events.emit(f(x));
        });

        return events;
    },
    filter: function (f) {
        var events = new Events;

        this.addListener(function (x) {
            if (f(x)) events.emit(x);
        });

        return events;
    },
    scan: function (a, f) {
        var events = new Events(a);

        this.addListener(function (x) {
            events.emit(a = f(a, x));
        });

        return events;
    },
    merge: function (that) {
        var events = new Events;

        this.addListener(function (x) {
            events.emit({ left: x });
        });

        that.addListener(function (y) {
            events.emit({ right: y });
        });

        return events;
    }
});

Now that that's out of the way let's talk about inheritance.

Timer Stream

Event streams come in different flavors. One of the most common type of event stream is a timer stream.

A timer stream periodically emits events. It can be paused and resumed at any time. It's useful for creating animations.

var TimerStream = augment(EventStream, function (uber) {
    this.constructor = function (interval) {
        uber.constructor.call(this);
        this.interval = interval;
    };

    this.start = function () {
        var self = this, now = Date.now();

        self.timeout = setTimeout(function () {
            loop.call(self, now);
        }, 0);

        return now;
    };

    this.stop = function () {
        clearTimeout(this.timeout);
        return Date.now();
    };

    function loop(time) {
        var self = this, now = Date.now(), next = time + self.interval;

        self.timeout = setTimeout(function () {
            loop.call(self, next);
        }, next - now);

        self.set(now);
    }
});

As you can see creating derived classes using augment is dead simple. Every class has a function body. Using a function as the class body has the following advantages:

  1. It eliminates the need for a for..in loop to copy the methods of the class.
  2. It allows augment to easily pass values to the class (e.g. concat and uber).
  3. It allows you to easily create private static data members (e.g. loop).

In the above TimerStream class we use the uber object passed to the class function body to call the base class constructor from the derived class constructor. The values passed to the class function body are:

  1. All the arguments after the base class and the function body passed to the augment function.
  2. The prototype object of the base class. Since it's always at the end of the argument list you can leave it out if you don't need it (as we left it out in the EventStream class).

Using uber you can call any method of the base class even if it's been overridden by the derived class. Here we used uber.constructor.call(this) to call the base class constructor from the derived class.

Conclusion

To recap we learned the following about classical inheritance using augment:

  1. Creating a derived class is as simple as passing the base class as the first argument to augment.
  2. The last argument passed to the function passed to augment is the prototype of the base class.
  3. The prototype of the base class can be used to call overridden base class methods.

That's all you will ever need to know about classical inheritance using augment.

Clone this wiki locally