Example: Compose Classes of Objects with `augment`

Creating a composition-based class structure using augment

Using augment

YUI().use('node', function(Y) {
    // This method is in the 'oop' module.  Since we require 'node'
    // for this example, and 'node' requires 'oop', the 'oop' module
    // will be loaded automatically.

The example: Any class can be an EventTarget

This example creates a custom class, then augments it with EventTarget. Using the packaged functionality of EventTarget, the code for Foo is able to focus on the functionality unique to its purpose.

YUI().use('node', function(Y) {
    // This method is in the 'oop' module.  Since we require 'node'
    // for this example, and 'node' requires 'oop', the 'oop' module
    // will be loaded automatically.

    var Foo = function() {
        /* code specific to Foo */
        this.publish('interestingMoment');
    };

    Foo.prototype.doSomething = function() {

        var eventData = {};

        // -- do something interesting, add results to eventData --

        eventData.statusText = 'bar';

        // notify the subscribers, passing the event data
        this.fire('interestingMoment', eventData);
    }

    Y.augment(Foo, Y.EventTarget);

    var foo = new Foo();

    // add some event listeners
    foo.on('interestingMoment', function (data) {
        var p = Y.one('#demo_p1');
        p.setHTML('I was notified of an interesting moment: ' + data.statusText);
    });

    foo.on('interestingMoment', function (data) {
        var p = Y.one('#demo_p2');
        p.setHTML('I was also notified of an interesting moment: ' + data.statusText);
    });

    Y.on('click', function() { 
        foo.doSomething();
    }, '#demo_btn');
});

Composition, not inheritance

If Foo were a part of a class hierarchy, it would be improper to include EventTarget in the inheritance chain, because its custom event functionality is not an intrinsic characteristic but rather an ancillary, generic capability that many classes share.

Unlike extended classes, the relationship between a class and the classes augmenting it is not an indication of type hierarchy. The intent of augment is to aid in extracting nonessential behaviors or behaviors shared by many classes, allowing for a composition-style class architecture.

Diagram showing class hierarchy, highlighting has-a relationship

This may appear similar to multiple inheritance, but it's not. augment simply adds the public methods and members from one class prototype to another class prototype. Instances of the augmented class will not pass instanceof tests for the class(es) which augmented it.

YUI().use('oop', function(Y) {

    function Foo() {}
    Foo.prototype.doSomething = function () { /* something */ };

    function Bar() {}
    Y.augment(Bar, Foo);

    var b = new Bar();
    if (b instanceof Bar) {} // true 
    if (b instanceof Foo) {} // FALSE
});