Altering the function by working with the source code strings can be quite simple. To do it for a specific instance, try:
eval(doSomething.toString().replace(/}\s*$/, ' return id; $&');
Now doSomething
returns the ID. I'm not normally a fan of eval
, but normal aspect oriented programming techniques don't apply here, due to the requirement for accessing a local variable.
If doSomething
already returns a value, try:
eval(doSomething.toString().replace(/}\s*$/, ' window.someID = id; $&');
To turn this into a function, we need to make the code evaluate in global scope:
function insertCode(func, replacer, pattern) {
var newFunc = func.toString().replace(pattern, replacer);
with (window) {
eval(newFunc);
}
}
function after(func, code) {
return insertCode(func, function (old) { code + old }, /}\s*$/ );
}
...
after(doSomething, 'return id;');
If you want to rewrite methods and anonymous functions bound to variables, change insertCodeBefore
to:
function insertCode(funcName, replacer, pattern) {
var newFunc = eval('window.' + funcName).toString().replace(pattern, replacer);
eval('window.' + funcName + '=' + newFunc);
}
...
function Foo() {}
Foo.prototype.bar = function () { var secret=0x09F91102; }
...
after('doSomething', 'return id;');
after('Foo.prototype.bar', 'return secret;');
Note the first argument to the functions are now strings. We can define other functions:
function before(func, code) {
return insertCode(func, function (old) {old + code}, /^function\s+\w+\([^)]*\)\s+{/);
}
function around(func, beforeCode, afterCode) {
before(func, beforeCode);
after(func, afterCode);
}