Inject javascript into a javascript function

前端 未结 7 1789
别跟我提以往
别跟我提以往 2021-02-04 13:25

I\'ve got a weird question in that I need to inject some javascript into another javascript function. I am using a framework which is locked so I can not change the existing fun

7条回答
  •  感情败类
    2021-02-04 14:04

    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 wrapping the body in a try ... finally:

    eval(doSomething.toString()
        .replace(/^function *\w* *\([^)]*\) *{/, '$& try {')
        .replace(/}\s*$/, '} finally { window.someID = id; } $&')
    );
    

    To turn this into a function, we need to make the code evaluate in global scope. Originally, this answer made use of with to change the scope of the eval, but this doesn't currently work in browsers. Instead, .call is used to change the scope of eval to 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; }');
    

    If you want to rewrite methods and anonymous functions bound to variables, change alter to:

    ...
        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;');
    

    Note the first argument to the functions are now strings. Further improvements could be made to handle methods that aren't accessible in global scope.

提交回复
热议问题