You only need to go along the eval / Function route if you need to support functions with any number of parameters. If you can set a reasonable upper limit (my example is 5), you can do the following:
var wrapFunction = function( func, code, where ){ var f; switch ( where ) { case 'after': f = function(t,a,r){ r = func.apply(t,a); code.apply(t,a); return r; } break; case 'around': f = function(t,a){ return code.call(t,func,a); } break; default: case 'before': f = function(t,a){ code.apply(t,a); return func.apply(t,a); } break; } switch ( func.length ) { case 0: return function(){return f(this, arguments);}; break; case 1: return function(a){return f(this, arguments);}; break; case 2: return function(a,b){return f(this, arguments);}; break; case 3: return function(a,b,c){return f(this, arguments);}; break; case 4: return function(a,b,c,d){return f(this, arguments);}; break; case 5: return function(a,b,c,d,e){return f(this, arguments);}; break; default: console.warn('Too many arguments to wrap successfully.'); break; } }
You can also extend this way of wrapping code by creating various where switches. I implemented before and after because they are most useful for my own project - and around only because it reminds me of lisp. Using this setting, you can also pass the shell ( var f ) to external code, which allows you to develop a system-like plugin for the where keywords, which means that you can easily extend or override wrapFunction support.
Obviously, you can change the way you actually wrap the code as you like, the key really uses a similar technique for 999 and AdrianLang, just without worrying about line building and switching to new Function .