122

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

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

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

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

4

6 回答 6

233

如果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,并将传入的任何参数作为单独的参数传递,而不管有多少。

于 2012-02-03T20:02:06.817 回答
32

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

var oldFunction = someFunction;

然后定义你自己的:

someFunction = function(){
  // do something before
  oldFunction();
  // do something after
};
于 2012-02-03T20:00:01.373 回答
10

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

var old_someFunction = someFunction;
someFunction = function(){
    alert('Hello');
    old_someFunction();
    alert('Goodbye');
}
于 2012-02-03T20:00:19.143 回答
6

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

var the_old_function = someFunction;
someFunction = function () {
    /* ..My new code... */
    the_old_function();
    /* ..More of my new code.. */
}
于 2012-02-03T20:01:13.430 回答
6

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

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

但这只是最简单的例子。处理参数、注释和返回值仍需要大量工作。此外,还有很多陷阱。
字符串| 切片| 索引| 上一个索引| 新功能

于 2015-07-18T23:46:34.577 回答
2

代理模式(由 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);

于 2019-01-26T15:43:47.103 回答