Constructor hacking for modularity

by James Greene

HTML

<h1>Constructor Hacking for Modularity</h1>

JavaScript

/* Core module */

var clients = [];

function ZeroClipboard() {
    if (typeof ZeroClipboard.Client === "function") {
        var client = ZeroClipboard.Client.apply(this, arguments);
        clients.push(client);
        return client;
    }
}

ZeroClipboard.Core = {
    setPendingText: function(text) {
        // TODO: Set `text` for Flash
    }
};




/* Core and/or other modules that add `ZeroClipboard.prototype.*` methods */

ZeroClipboard.prototype.setText = function(text) {
    ZeroClipboard.Core.setPendingText(text);
    return this;
};



/* Client module */

// EXTREMELY IMPORTANT
// This instance must be created before the `ZeroClipboard.Client` function is defined
var ZC_ClientProto = new ZeroClipboard();

ZeroClipboard.Client = function (val1, val2) {
    // EXTREMELY IMPORTANT
    // Enforce that the constructor is called with the `new` operator.
    // The guts of the `ZeroClipboard` function will NOT be calling it with the `new` operator.
    // This allows the arguments to be determined by the author of `ZeroClipboard.Client`.
    if (!(this instanceof ZeroClipboard.Client)) {
        return new ZeroClipboard.Client(val1, val2);
    }
 
    console.log("instanceof Client? " + (this instanceof ZeroClipboard.Client));
    console.log("instanceof ZC? " + (this instanceof ZeroClipboard));
    
    for (var i = 0, len = arguments.length; i < len; i++) {
        console.log("arg " + i + " = " + JSON.stringify(arguments[i]));
    }
}
// EXTREMELY IMPORTANT
// This will ensure that the `Client` instance gets all of the `ZeroClipboard.prototype.*` methods
ZeroClipboard.Client.prototype = ZC_ClientProto;
// EXTREMELY IMPORTANT
// This will ensure that the `Client` instances understand their inheritance structure
ZeroClipboard.Client.prototype.constructor = ZeroClipboard.Client;




/* Actual usage */

var client = new ZeroClipboard("foo", "bar");
client.setText("blah");