ソース コード文字列を操作して関数を変更するのは、非常に簡単です。特定のインスタンスに対してそれを行うには、次を試してください。
eval(doSomething.toString().replace(/}\s*$/, ' return id; $&'));
doSomethingIDを返すようになりました。私は通常、 のファンではありませんが、ローカル変数にアクセスする必要があるためeval、通常のアスペクト指向プログラミング手法はここでは適用されません。
すでに値が返されている場合doSomethingは、本体を でラップしてみてくださいtry ... finally。
eval(doSomething.toString()
.replace(/^function *\w* *\([^)]*\) *{/, '$& try {')
.replace(/}\s*$/, '} finally { window.someID = id; } $&')
);
これを関数に変換するには、コードをグローバル スコープで評価する必要があります。もともと、この回答はwithのスコープを変更するために を使用しevalていましたが、これは現在ブラウザーでは機能しません。代わりに、.callのスコープを に変更するために使用されevalますwindow。
(function () {
var begin = /^function\s*\w*\s*\([^)]*\)\s*{/,
end = /}\s*$/;
function alter(func, replacer) {
var newFunc = replacer(func.toString());
eval.call(window, newFunc);
}
function insertCode(func, replacer, pattern) {
alter(func, function (source) {
return source.replace(pattern, replacer);
});
};
/* Note: explicit `window` to mark these as globals */
window.before = function (func, code) {
return insertCode(func, '$& ' + code, begin);
};
window.after = function (func, code) {
return insertCode(func, code + ' $&', end);
};
window.around = function (func, pre, post) {
/* Can't simply call `before` and `after`, as a partial code insertion may produce a syntax error. */
alter(func, function(source) {
return source
.replace(begin, '$& ' + pre)
.replace(end, post + ' $&');
});
};
})();
...
after(doSomething, 'return id;');
/* or */
around(doSomething, 'try {', '} finally { window.someID = id; }');
変数にバインドされたメソッドと無名関数を書き直したい場合は、次のように変更alterします。
...
function alter(func, replacer) {
var newFunc = replacer(eval('window.' + funcName).toString());
eval.call(window, newFunc);
}
...
function Foo() {}
Foo.prototype.bar = function () { var secret=0x09F91102; }
...
after('Foo.prototype.bar', 'return secret;');
関数の最初の引数が文字列になっていることに注意してください。グローバル スコープでアクセスできないメソッドを処理するために、さらなる改善が行われる可能性があります。