【问题标题】:Append code to the end of an existing function将代码附加到现有函数的末尾
【发布时间】:2012-06-28 16:09:20
【问题描述】:

每当函数 foo() 触发时,我都需要触发函数 bar()。我无法控制函数 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 ;
}
}

例如:

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

这让我觉得这是一个糟糕的想法 - 但它确实有效。有人可以指出一个更好(更安全)的方向吗?

编辑:foo 不是一个特定的函数,而是我最终处理的许多函数。它们不会在页面中动态更改。但它们可能会不时更改(例如表单验证要求)。

解决方案: 我选择了亚当答案的修改版本。它并不完美,但比我拥有的要好:

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

注意。注意 IE6/7 中一些没有 .apply() 方法的本机函数。

【问题讨论】:

标签: javascript eval


【解决方案1】:

您可以使用调用原始函数的自定义函数覆盖 foo

例如

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

您还应该通过替换函数将foo 接受的任何参数传递给它。

【讨论】:

  • 比我的更简单、更安全。随着argumentsreturn 的更改,这可能在大多数情况下都有效。
  • 这个解决方案会导致我的堆栈溢出。如果您有同样的经历,下面 xdazz 的解决方案对我有用。
【解决方案2】:

您可以将一些新代码附加或预先添加到现有函数,只需合并它们,例如:

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);
    }
}



基本示例如下:

// 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



注意,合并函数会尝试将预期的“this”应用于合并的部分,否则您也可以简单地将所需的“this”传递给它们因为您可以处理相对参数。
更一般的示例可能如下:

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

【讨论】:

    【解决方案3】:

    你可以这样做: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();
    

    【讨论】:

      【解决方案4】:
      function extend(fn,code){
        return function(){
          fn.apply(fn,arguments)
          code.apply(fn,argumnets)
        }
      }
      

      并像这样使用它:

      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”

      【讨论】:

        【解决方案5】:

        嗯,我也有这个问题,你提到了

        我经常遇到这种情况(我讨厌它)。

        您介意我问这种情况在什么情况下不断发生吗?它是在公司范围内,还是在个人项目范围内?你显然有一个冷静的头脑,并且知道你正在做的事情与众不同,所以我想知道是否有其他解决方案。

        我问的原因是;这种方法可能会引发一系列问题。例如,如果foo 失败,或者foo 在评估中返回值怎么办?通过简单地将bar 附加到实际函数并不能保证它会执行。另一方面,预置它意味着它更多可能被执行,但在我看来仍然不是一个好方法。

        您是否考虑过修改函数foo?我知道这似乎是一个愚蠢的问题,但如果您在整个过程中遇到类似问题,这可能是值得的。如果您想让事情保持抽象,您可以采用“事件处理程序”方法,其中foo 触发window 上的事件,然后触发bar,这是否适用于您的情况。

        或者,如果您知道foo 是什么以及它的作用,您可以挂钩到它的原型(如果它是一个对象),然后适当地修改那里的代码。但是,您确实提到此功能可以更改,这可能会使此选项变得多余,但它仍然是一种可能的解决方案。

        【讨论】:

        • 这是一个(多)公司规模,我无法控制foo 的功能。通常还有其他解决方法(例如 setTimeout 来检查函数的结果)。但我认为在窗口上触发事件听起来比我所拥有的略有改进。
        猜你喜欢
        • 2011-02-04
        • 2014-03-06
        • 1970-01-01
        • 2023-01-10
        • 2017-06-15
        • 2011-04-06
        • 2023-03-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多