简体   繁体   English

将代码附加到现有函数的末尾

[英]Append code to the end of an existing function

I need to trigger function bar() whenever function foo() fires. 我需要在函数foo()触发时触发函数bar()。 I have no control over function foo or whether it will change in the future. 我无法控制函数foo或将来是否会改变。 I have this situation regularly (and I hate it). 我经常有这种情况(我讨厌它)。

I wrote this function to add my code to the end of function foo: 我写了这个函数来将我的代码添加到函数foo的末尾:

function appendToFunction(fn,code){ 
if(typeof fn == 'function'){
    var fnCode = fn.toString() ;
    fnCode = fnCode.replace(/\}$/,code+"\n}") ;
    window.eval(fnCode);                    // Global scope
    return true ;
}
else{
    return false ;
}
}

eg: 例如:

appendToFunction(foo,"bar();");

This strikes me as a terrible idea - but it works. 这对我来说是一个可怕的想法 - 但它确实有效。 Can somebody point me in a better (safer) direction please. 有人可以指出我更好(更安全)的方向。

EDIT: foo is not a specific function, but many functions that I wind up dealing with. 编辑: foo不是一个特定的功能,但我最终处理的功能很多。 They don't change dynamically in the page. 它们不会在页面中动态更改。 But they may be changed (eg. form validation demands) from time to time. 但它们可能会不时地改变(例如,形式验证要求)。

Solution : I settled on a modified version of Adam's Answer. 解决方案 :我选择了Adam的答案的修改版本。 It's not perfect, but it's better than what I had: 它并不完美,但它比我的更好:

var oldFoo = foo ;
foo = function(){
        var result = oldFoo.apply(this, arguments);
        bar();
        return result ;
}

NB. NB。 Watch out for some native functions in IE6/7 that don't have an .apply() method. 注意IE6 / 7中没有.apply()方法的一些本机函数。

You can just override foo with a custom function that calls the original. 您可以使用调用原始函数的自定义函数覆盖foo

Eg 例如

var old_foo = foo;
foo = function() {
  old_foo();
  bar();
}

You should also pass any arguments foo takes into it via your replacement function. 您还应该通过替换函数传递foo接收到的任何参数。

function extend(fn,code){
  return function(){
    fn.apply(fn,arguments)
    code.apply(fn,argumnets)
  }
}

and use it like this: 并像这样使用它:

function appendToFunction(fn,code){ 
    if(typeof fn == 'function'){
        var fnCode = fn.toString() ;
        fnCode = fnCode.replace(/\}$/,code+"\n}") ;
        window.eval(fnCode);                    // Global scope
        return true ;
    }
    else{
        return false ;
    }
}

appendToFunction = extend(appendToFunction,function(){/*some code*/});

this will give you the same "this" in both functions 这将在两个函数中给你相同的“this”

You could do something like this: THE DEMO . 你可以这样做:演示

function foo() {
 console.log('foo');
}

function appendToFunction(fn, callback) {
  window[fn] = (function(fn){
    return function() {
      fn();
      callback();
    }
 }(window[fn]));
}

appendToFunction('foo', function(){console.log('appended!')});

foo();

Hmm, this concerns me as well, you mentioned that 嗯,这也让我很担心,你提到了这一点

I have this situation regularly (and I hate it). 我经常有这种情况(我讨厌它)。

Do you mind if I ask in what scenario this keeps occurring? 你介意我问在这种情况下会持续发生的情况吗? Is it in a corporate scale, or on a personal project scope? 它是在公司范围内,还是在个人项目范围内? You've clearly got a level head on your shoulders and know that what you're doing is out of the ordinary, so I'm wondering if there is an alternatively solution. 你显然已经掌握了一个水平的头,知道你正在做的事与众不同,所以我想知道是否有一个替代解决方案。

The reason I ask is; 我问的原因是; this approach could potentially open a can of problems. 这种方法可能会引发一系列问题。 What if foo fails for example, or if foo returns a value mid evaluation? 如果foo失败,或者foo在评估中返回值,该怎么办? By simply appending bar to the actual function doesn't guarantee it will execute. 通过简单地将bar附加到实际函数并不能保证它将执行。 Pre-pending it on the other hand means it's more likely to be executed, but still in my opinion isn't a good approach. 另一方面预备它意味着它更有可能被执行,但在我看来仍然不是一个好方法。

Have you considered revising the function foo ? 你考虑修改函数foo吗? I know this might seem like a silly question, but it might be worth it if you're encountering similar problems throughout. 我知道这可能看起来像一个愚蠢的问题,但如果你遇到类似的问题,它可能是值得的。 If you want to keep things abstracted you could adopt an "event handler" approach, whereby foo triggers an event on the window , which in turn then triggers bar , would this work in your case. 如果你想保持抽象的东西你可以采用“事件处理程序”的方法, foo触发window上的事件,然后触发bar ,这将在你的情况下工作。

Alternatively, if you know what foo is, and what it does, you could hook into it's prototype if it's an object, and then amend the code there appropriately. 或者,如果你知道foo是什么,以及它做了什么,你可以挂钩它的原型,如果它是一个对象,然后适当修改代码。 You did however mention that this function is open to change, which may make this option redundant, but it's a possible solution nonetheless. 但是你提到这个功能是可以改变的,这可能会使这个选项变得多余,但它仍然是一个可能的解决方案。

You can append or prepend some new code to an existing function just merging them using for example: 您可以将一些新代码附加或添加到现有函数中,只需使用它们合并它们,例如:

function mergeFunctions(function1, function2, instance1, instance2, numberOfArgumentsToPassToFunc1) {
    return function() {
        var _arguments  = Array.prototype.slice.apply(arguments);
        var _arguments1 = _arguments.slice(0, numberOfArgumentsToPassToFunc1);
        var _arguments2 = _arguments.slice(numberOfArgumentsToPassToFunc1);
        var that = this;
        (function(function1, function2) {
            if (typeof function1 == "function") {
                if (typeof instance1 != "undefined") {
                    function1.apply(instance1, _arguments1);
                }
                else if (that == window) {
                    function1.apply(function1, _arguments1);
                }
                else {
                    var compare = mergeFunctions(function(){}, function(){});
                    if (that.toString() == compare.toString()) {
                        function1.apply(function1, _arguments1);
                    }
                    else {
                        function1.apply(that, _arguments1);
                    }
                }
            }
            if (typeof function2 == "function") {
                if (typeof instance2 != "undefined") {
                    function2.apply(instance2, _arguments2);
                }
                else if (that == window) {
                    function2.apply(function2, _arguments2);
                }
                else {
                    var compare = mergeFunctions(function(){}, function(){});
                    if (that.toString() == compare.toString()) {
                        function2.apply(function2, _arguments2);
                    }
                    else {
                        function2.apply(that, _arguments2);
                    }
                }
            }
        })(function1, function2);
    }
}



A basic example would be the following: 一个基本的例子如下:

// Original function:
var someFunction = function(){
    console.log("original content");
};

// Prepend new code:
// --------------------------------------------------------
someFunction = mergeFunctions(function() {
    console.log("--- prepended code");
}, someFunction);

// Testing:
someFunction();

// Outout:
// [Log] --- prepended code
// [Log] original content


// Append new code:
// --------------------------------------------------------
someFunction = mergeFunctions(someFunction, function() {
    console.log("appended code");
});

// Testing:
someFunction();

// Output:
// [Log] --- prepended code
// [Log] original content
// [Log] appended code



Note that the merging function tries to apply the expected 'this' to the merged parts, otherwise you can just simply pass the wanted 'this' to them, as well as you can handle the relative arguments. 请注意 ,合并函数会尝试将预期的“this”应用于合并的部分,否则您只需将所需的“this”传递给它们,您就可以处理相对的参数。
A more general example could be the following: 更一般的例子如下:

function firstPart(a, b) {
    console.log("--- first part");
    console.log("'this' here is:");
    console.log(this.name);
    console.log("a: "+a);
    console.log("b: "+b);
}

function MyObject() {
    this.x = "x property of MyObject";
}

MyObject.prototype.secondPart = function (y) {
    console.log("");
    console.log("--- second part");
    console.log("'this' here is:");
    console.log(this.name);
    this.x = y;
    console.log("x: "+this.x);
}

MyObject.prototype.merged = mergeFunctions(firstPart, MyObject.prototype.secondPart, firstPart, MyObject, 2);

// Testing
var test = new MyObject();
test.merged("a parameter", "b parameter", "x parameter overrides x property of MyObject");

// Console output:
// [Log] --- first part
// [Log] 'this' here is:
// [Log] firstPart
// [Log] a: a parameter
// [Log] b: b parameter
// [Log] 
// [Log] --- second part
// [Log] 'this' here is:
// [Log] MyObject
// [Log] x: x parameter overrides x property of MyObject

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM