以编程方式将代码添加到javascript函数


114

我试图自定义现有的JS库,而不修改原始JS代码。这段代码将加载一些我可以访问的外部JS文件,而我想做的就是更改原始文件中包含的功能之一,而无需将整个内容复制并粘贴到第二个JS文件中。
因此,例如,禁区JS可能具有以下功能:

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

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

我不确定这是否可行,但我想我会检查一下。


3
的第一个答案应该可以帮助您
DarkAjax

您是否想要像回调函数之类的东西?
sinemetu1 '02

Answers:


219

如果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;
    };
})();

这是小提琴


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


10
这个答案确实应该是最重要的答案-它保留了相关功能的功能... +1。
里德2012年

17
使用+1 apply:这是真正解决问题的唯一答案。
lonesomeday '02

2
@minitech:什么...您不熟悉JavaScript的funciton关键字?;)感谢您的编辑

1
@gdoron:我刚刚添加了一条评论。除非我现在真的很困惑,否则我不知道任何不接受实际Arguments对象作为的第二个参数的浏览器.apply()。但是,如果它是类似于jQuery对象的类似Array的对象,那么是的,某些浏览器会引发错误

2
这个答案恰好解决了使用实例对象控制通过YouTube Iframe API嵌入的各个YouTube视频的问题。您不知道我试图创建一个类以独特的模块化方式处理每个视频数据的类时,API要求回调是单个全局函数这一事实已经解决了多长时间。你是我今天的英雄。
Carnix

31

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

var oldFunction = someFunction;

然后定义自己的:

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

9
如果您的函数是一种方法,则需要使用apply它来调用它。见上午的答案。
hugomg

它对我有用,但是需要someFunctionwindow.someFunction上面的代码替换。原因是我的函数是在jquery $(document).ready()处理程序中声明的。
尼尔森

10

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

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

6

我不知道是否可以更新该功能,但是根据如何引用它,可以在其位置上制作一个新功能:

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

但这只是最简单的例子。处理参数,注释和返回值仍需要大量工作。此外,仍然存在许多陷阱。
toString | | indexOf | lastIndexOf | 新功能


1

可以将代理模式(由user1106925使用)放在函数内。我在下面编写的代码可以处理不在全局范围内的函数,甚至可以用于原型。您可以这样使用它:

extender(
  objectContainingFunction,
  nameOfFunctionToExtend,
  parameterlessFunctionOfCodeToPrepend,
  parameterlessFunctionOfCodeToAppend
)

在下面的代码段中,您可以看到我使用该函数扩展了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);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.