【问题标题】:Adding code to a javascript function programmatically以编程方式将代码添加到 javascript 函数
【发布时间】:2012-02-26 10:15:06
【问题描述】:

我正在尝试在不修改原始 JS 代码的情况下自定义现有的 JS 库。这段代码加载到我可以访问的几个外部 JS 文件中,我想做的是更改原始文件中包含的函数之一,而无需将整个内容复制并粘贴到第二个 JS 文件中。
所以举例来说,禁区JS可能有这样一个函数:

var someFunction = function(){
    alert("done");
}

我希望能够以某种方式将一些 JS 代码附加或预先添加到该函数中。原因主要是在原始的 untouchable JS 中,函数非常庞大,如果该 JS 得到更新,我覆盖它的函数将过时。

我不完全确定这是可能的,但我想我会检查一下。

【问题讨论】:

  • this的第一个回答应该对你有帮助
  • 你想要一个回调函数之类的东西吗?

标签: javascript merge append user-defined-functions prepend


【解决方案1】:

如果someFunction 是全局可用的,那么您可以缓存该函数,创建您自己的函数并让您调用它。

如果这是原版的话……

someFunction = function() {
    alert("done");
}

你会这样做......

someFunction = (function() {
    var cached_function = someFunction;

    return function() {
        // your code

        var result = cached_function.apply(this, arguments); // use .apply() to call it

        // more of your code

        return result;
    };
})();

Here's the fiddle


请注意,我使用.apply 调用缓存函数。这让我可以保留 this 的预期值,并将传入的任何参数作为单独的参数传递,而不管有多少。

【讨论】:

  • 这个答案应该是最重要的——它保留了相关函数的功能......来自我的 +1。
  • +1 用于使用apply:这是真正解决问题的唯一答案。
  • @minitech: 什么...你不熟悉 JavaScript 的 funciton 关键字吗? ;) 感谢您的编辑
  • @gdoron:我刚刚添加了一条评论。除非我现在真的很困惑,否则我不知道有任何浏览器不接受实际的 Arguments 对象作为.apply() 的第二个参数。但是如果它是一个类似 Array 的对象,例如 jQuery 对象,那么是的,一些浏览器会抛出错误
  • 这个答案恰好解决了使用实例对象控制通过 YouTube Iframe API 嵌入的各个 YouTube 视频的问题。您不知道当我尝试创建一个类来以独特的模块化方式处理每个视频的数据时,我一直在尝试解决 API 要求它的回调成为单个全局函数这一事实多长时间。你是我今天的英雄。
【解决方案2】:

首先将实际函数存储在变量中..

var oldFunction = someFunction;

然后定义你自己的:

someFunction = function(){
  // do something before
  oldFunction();
  // do something after
};

【讨论】:

  • 如果你的函数是一个方法,你需要使用apply来调用它。见我的回答。
  • 它对我有用,但需要在上面的代码中用window.someFunction 替换someFunction。原因是我的函数是在 jquery $(document).ready() 处理程序中声明的。
【解决方案3】:

您可以创建一个调用您的代码的函数,然后调用该函数。

var old_someFunction = someFunction;
someFunction = function(){
    alert('Hello');
    old_someFunction();
    alert('Goodbye');
}

【讨论】:

    【解决方案4】:

    不知道能不能更新函数,但是根据引用的方式,可以在它的位置新建一个函数:

    var the_old_function = someFunction;
    someFunction = function () {
        /* ..My new code... */
        the_old_function();
        /* ..More of my new code.. */
    }
    

    【讨论】:

      【解决方案5】:

      还有。如果要更改本地上下文,则必须重新创建函数。例如:

      var t = function() {
          var a = 1;
      };
      
      var z = function() {
          console.log(a);
      };
      

      现在

      z() // => log: undefined
      

      然后

      var ts = t.toString(),
          zs = z.toString();
      
      ts = ts.slice(ts.indexOf("{") + 1, ts.lastIndexOf("}"));
      zs = zs.slice(zs.indexOf("{") + 1, zs.lastIndexOf("}"));
      
      var z = new Function(ts + "\n" + zs);
      

      z() // => log: 1
      

      但这只是最简单的例子。处理参数、cmets 和返回值仍需要大量工作。另外,还有很多坑。
      toString | slice | indexOf | lastIndexOf | new Function

      【讨论】:

        【解决方案6】:

        代理模式(由 user1106925 使用)可以放在函数中。我在下面写的那个适用于不在全局范围内的函数,甚至适用于原型。你可以这样使用它:

        extender(
          objectContainingFunction,
          nameOfFunctionToExtend,
          parameterlessFunctionOfCodeToPrepend,
          parameterlessFunctionOfCodeToAppend
        )
        

        在下面的sn-p中,你可以看到我使用函数来扩展test.prototype.doIt()。

        // allows you to prepend or append code to an existing function
        function extender (container, funcName, prepend, append) {
        
            (function() {
        
                let proxied = container[funcName];
        
                container[funcName] = function() {
                    if (prepend) prepend.apply( this );
                    let result = proxied.apply( this, arguments );
                    if (append) append.apply( this );
                    return result;
                };
        
            })();
        
        }
        
        // class we're going to want to test our extender on
        class test {
            constructor() {
                this.x = 'instance val';
            }
            doIt (message) {
                console.log(`logged: ${message}`);
                return `returned: ${message}`;
            }
        }
        
        // extends test.prototype.doIt()
        // (you could also just extend the instance below if desired)
        extender(
            test.prototype, 
            'doIt', 
            function () { console.log(`prepended: ${this.x}`) },
            function () { console.log(`appended: ${this.x}`) }
        );
        
        // See if the prepended and appended code runs
        let tval = new test().doIt('log this');
        console.log(tval);

        【讨论】:

          猜你喜欢
          • 2018-07-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-08
          • 2018-12-04
          • 1970-01-01
          相关资源
          最近更新 更多