var EventDispatcher = (function() { var api = { addEventListener: function(event, callback) { initialize(this); if (!this.eventListeners[event]) this.eventListeners[event] = []; this.eventListeners[event].push(callback); }, dispatchEvent: function(event) { initialize(this); (this.eventListeners[event] || []). forEach(function(callback) { callback(event); }); } }; // Pass bound object in instead of binding function, slightly less overhead var initialize = function(o) { if (o.eventListeners) return; o.eventListeners = {}; }; return api; })(); var MyClass = function(color) { this.color = color; }; // Lifted from Prototype, used for copying references to functions onto a new sterile prototype Object.extend = function(dst, src) { for (var p in src) dst[p] = src[p]; return dst; }; // Copy properties from EventDispatcher to our own prototype // Not strictly necessary, but this allows for multiple behaviors to be composed // without modifying EventDispatcher's prototype MyClass.prototype = Object.extend({}, EventDispatcher); var myObj = new MyClass('pink'); myObj.addEventListener('event1', function() { console.log('Event 1 fired'); }); myObj.dispatchEvent('event1');