function actsAsDecorator(object) { object.setupDecoratorFor = function(method) { if (! ('original_' + method in object) ) { object['original_' + method] = object[method]; object['before_' + method] = [ ]; object['after_' + method] = [ ]; object[method] = function() { var i; var b = this['before_' + method]; var a = this['after_' + method]; var rv; for (i = 0; i < b.length; i++) { b[i].call(this, arguments); } rv = this['original_' + method].apply(this, arguments); for (i = 0; i < a.length; i++) { a[i].call(this, arguments); } return rv; } } }; object.before = function(method, f) { object.setupDecoratorFor(method); object['before_' + method].unshift(f); }; object.after = function(method, f) { object.setupDecoratorFor(method); object['after_' + method].push(f); }; } /** Invoking */ function Test(){ this.say1 = function(s){ alert(s); } this.say2 = function(s){ alert(s); } } var t = new Test(); actsAsDecorator(t); t.before("say1",beforeHander); t.after("say2",afterHander); test();